home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / x11 / rpg / crossfir.92 / crossfir / crossfire-0.92.5 / server / apply.c < prev    next >
C/C++ Source or Header  |  1996-07-24  |  74KB  |  2,439 lines

  1. /*
  2.  * static char *rcsid_apply_c =
  3.  *   "$Id: apply.c,v 1.51 1996/07/24 07:30:42 master Exp master $";
  4.  */
  5. /*
  6.     CrossFire, A Multiplayer game for X-windows
  7.  
  8.     Copyright (C) 1994 Mark Wedel
  9.     Copyright (C) 1992 Frank Tore Johansen
  10.  
  11.     This program is free software; you can redistribute it and/or modify
  12.     it under the terms of the GNU General Public License as published by
  13.     the Free Software Foundation; either version 2 of the License, or
  14.     (at your option) any later version.
  15.  
  16.     This program is distributed in the hope that it will be useful,
  17.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.     GNU General Public License for more details.
  20.  
  21.     You should have received a copy of the GNU General Public License
  22.     along with this program; if not, write to the Free Software
  23.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  24.  
  25.     The author can be reached via e-mail to mwedel@pyramid.com
  26. */
  27.  
  28. #include <global.h>
  29. #include <living.h>
  30. #include <spells.h>
  31. #include <skills.h>
  32. #if defined(SunArchitecture) && !(OSMajorVersion == 5)
  33. #include <sys/types.h>
  34. #endif
  35.  
  36. #ifndef __CEXTRACT__
  37. #include <sproto.h>
  38. #endif
  39. #ifdef SOUND_EFFECTS
  40. #include <sounds.h>
  41. #endif
  42.  
  43. #if defined(vax) || defined(ibm032)
  44. size_t strftime(char *, size_t, const char *, const struct tm *);
  45. time_t mktime(struct tm *);
  46. #endif
  47.  
  48. void draw_find(object *op, object *find) {
  49.   new_draw_info_format(NDI_UNIQUE, 0, op, "You find %s in the chest.",
  50.     query_name(find));
  51. }
  52.  
  53. int apply_id_altar(object *money, object *altar)
  54. {
  55.     object *id, *pl;
  56.     int success=0;
  57.  
  58.     /* Check for MONEY type is a special hack - it prevents 'nothing needs
  59.      * identifying' from being printed out more than it needs to be.
  60.      */
  61.     if (!check_altar_sacrifice(altar) || money->type!=MONEY) return 0;
  62.  
  63.     pl=get_map_ob(altar->map, altar->x, altar->y);
  64.     while (pl!=NULL && pl->type!=PLAYER)
  65.     pl=pl->above;
  66.     if (pl==NULL) {
  67.     LOG(llevError,"Identify Altar: Can't find player!.\n");
  68.     return 0;
  69.     }
  70.     for (id=pl->inv; id; id=id->below) {
  71.     if (!QUERY_FLAG(id, FLAG_IDENTIFIED) && !id->invisible && 
  72.         need_identify(id)) {
  73.         if (check_altar(altar)) {
  74.             identify(id);
  75.             new_draw_info_format(NDI_UNIQUE, 0, pl,
  76.             "You have %s.", long_desc(id));
  77.                 if (id->msg) {
  78.                 new_draw_info(NDI_UNIQUE, 0,pl, "The item has a story:");
  79.                 new_draw_info(NDI_UNIQUE, 0,pl, id->msg);
  80.             }
  81.             success=1;
  82.             /* If no more money, might as well quit now */
  83.             if (!check_altar_sacrifice(altar)) break;
  84.         }
  85.         else {
  86.             LOG(llevError,"check_id_altar:  Couldn't do sacrifice when we should have been able to\n");
  87.             break;
  88.         }
  89.     }
  90.     }
  91.     if (!success) new_draw_info(NDI_UNIQUE, 0,pl,"You have nothing that needs identifying");
  92.     return 1;
  93. }
  94.  
  95. int apply_potion(object *op, object *tmp)
  96. {
  97.     int got_one=0;
  98.  
  99.     if(op->type!=PLAYER)
  100.       return 0; /* This might change */
  101.  
  102.     if(QUERY_FLAG(tmp, FLAG_UNPAID)) {
  103.       new_draw_info(NDI_UNIQUE,0,op,"You should pay for it first.");
  104.       return 0;
  105.     }
  106.     if (!QUERY_FLAG(tmp, FLAG_IDENTIFIED))
  107.       identify(tmp);
  108.  
  109.     if (tmp->attacktype & AT_DEPLETE) { /* Potion of restoration */
  110.       object *depl;
  111.       archetype *at;
  112.  
  113.       if (QUERY_FLAG(tmp, FLAG_CURSED) || QUERY_FLAG(tmp, FLAG_DAMNED)) {
  114.     drain_stat(op);
  115.         fix_player(op);
  116.         decrease_ob(tmp);
  117.         return 1;
  118.       }
  119.       if ((at = find_archetype("depletion"))==NULL) {
  120.     LOG(llevError,"Could not find archetype depletion");
  121.     return 0;
  122.       }
  123.       depl = present_arch_in_ob(at, op);
  124.       if (depl!=NULL) {
  125.     int i;
  126.         for (i = 0; i < 7; i++)
  127.           if (get_attr_value(&depl->stats, i)) {
  128.             new_draw_info(NDI_UNIQUE,0,op, restore_msg[i]);
  129.           }
  130.     remove_ob(depl);
  131.     free_object(depl);
  132.         fix_player(op);
  133.       }
  134.       else
  135.         new_draw_info(NDI_UNIQUE,0,op, "You feel a great loss...");
  136.  
  137.       decrease_ob(tmp);
  138.       return 1;
  139.     }
  140.     if(tmp->attacktype&AT_GODPOWER) {
  141.     int i;
  142.  
  143.     for(i=1;i<MIN(11,op->level);i++) {
  144.         if (QUERY_FLAG(tmp,FLAG_CURSED) || QUERY_FLAG(tmp,FLAG_DAMNED)) {
  145.         if (op->contr->levhp[i]!=1) {
  146.             op->contr->levhp[i]=1;
  147.             break;
  148.         }
  149.         if (op->contr->levsp[i]!=1) {
  150.             op->contr->levsp[i]=1;
  151.             break;
  152.         }
  153.         if (op->contr->levgrace[i]!=1) {
  154.             op->contr->levgrace[i]=1;
  155.             break;
  156.         }
  157.         }
  158.         else {
  159.              if(op->contr->levhp[i]<9) { 
  160.                  op->contr->levhp[i]=9;
  161.                  break;
  162.              }
  163.              if(op->contr->levsp[i]<6) { 
  164.                  op->contr->levsp[i]=6;
  165.                  break;
  166.              }
  167.              if(op->contr->levgrace[i]<3) {
  168.                  op->contr->levgrace[i]=3;
  169.                  break;
  170.              }
  171.          }
  172.      }
  173.     /* Just makes checking easier */
  174.     if (i<MIN(11, op->level)) got_one=1;
  175.     if (!QUERY_FLAG(tmp,FLAG_CURSED) && !QUERY_FLAG(tmp,FLAG_DAMNED)) {
  176.         if (got_one) {
  177.         fix_player(op);
  178.         new_draw_info(NDI_UNIQUE,0,op,"The Gods smile upon you and remake you");
  179.         new_draw_info(NDI_UNIQUE,0,op,"a little more in their image.");
  180.             new_draw_info(NDI_UNIQUE,0,op,"You feel a little more perfect.");
  181.         }
  182.         else
  183.         new_draw_info(NDI_UNIQUE,0,op,"The potion had no effect - you are already perfect");
  184.     }
  185.     else {    /* cursed potion */
  186.         if (got_one) {
  187.         fix_player(op);
  188.         new_draw_info(NDI_UNIQUE,0,op,"The Gods are angry and punish you.");
  189.         }
  190.         else 
  191.         new_draw_info(NDI_UNIQUE,0,op,"You are fortunate that you are so pathetic.");
  192.     }
  193.     decrease_ob(tmp);
  194.     return 1;
  195.     }
  196.  
  197.     /* protection/immunity granting potions */
  198.     if(tmp->immune||tmp->protected) {
  199.       object *force;
  200. #if 0    /* Allow more than 1 force to work at a time */
  201.       /* This is copied from change_abil(), should be moved to common func. */
  202.       if((force=present_in_ob(FORCE,op))!=NULL)
  203.         remove_force(force);
  204. #endif
  205.  
  206.       force=get_archetype("force");
  207.       if(QUERY_FLAG(tmp, FLAG_CURSED) || QUERY_FLAG(tmp, FLAG_DAMNED)) {
  208.         force->vulnerable = tmp->immune | tmp->protected;
  209. /* Why set force->type to 0?  This makes the result permanent */
  210. /*        force->type = 0; */
  211.         force->stats.food*=10;
  212.       } else {
  213.         force->immune=tmp->immune;
  214.         force->protected=tmp->protected;
  215.       }
  216.       force->speed_left= -1;
  217.       force = insert_ob_in_ob(force,op);
  218.       SET_FLAG(force,FLAG_APPLIED);
  219.       change_abil(op,force);
  220.       decrease_ob(tmp);
  221.       return 1;
  222.     }
  223.  
  224.     /* A potion that casts a spell.  Healing, restore spellpoint (power potion)
  225.      * and heroism all fit into this category.
  226.      */
  227.     if (tmp->stats.sp) {
  228.       if(QUERY_FLAG(tmp, FLAG_CURSED) || QUERY_FLAG(tmp, FLAG_DAMNED)) {
  229.         new_draw_info(NDI_UNIQUE,0,op, "Yech!  Your lungs are on fire!");
  230.         cast_spell(op,tmp, 0, 3, 0, spellPotion,NULL);
  231.       } else
  232.         cast_spell(op,tmp, 0, tmp->stats.sp, 0, spellPotion,NULL);
  233.       decrease_ob(tmp);
  234.       fix_player(op);
  235.       return 1;
  236.     }
  237.  
  238.     /* Only thing left are the stat potions */
  239.       if(QUERY_FLAG(tmp, FLAG_CURSED) || QUERY_FLAG(tmp, FLAG_DAMNED))
  240.     CLEAR_FLAG(tmp, FLAG_APPLIED);
  241.       else
  242.     SET_FLAG(tmp, FLAG_APPLIED);
  243.       if(!change_abil(op,tmp))
  244.         new_draw_info(NDI_UNIQUE,0,op,"Nothing happened.");
  245.  
  246.       /* CLEAR_FLAG is so that if the character has other potions
  247.        * that were grouped with the one consumed, his
  248.        * stat will not be raised by them.  fix_player just clears
  249.        * up all the stats.
  250.        */
  251.       CLEAR_FLAG(tmp, FLAG_APPLIED);
  252.       fix_player(op);
  253.       decrease_ob(tmp);
  254.       return 1;
  255. }
  256.  
  257. /****************************************************************************
  258.  * Weapon improvement code follows
  259.  ****************************************************************************/
  260.  
  261. int check_item(object *op,char *item)
  262. {
  263.   int count=0;
  264.  
  265.  
  266.   if (item==NULL) return 0;
  267.   op=op->below;
  268.   while(op!=NULL) {
  269.     if (strcmp(op->arch->name,item)==0){
  270.       if (!QUERY_FLAG (op, FLAG_CURSED) && !QUERY_FLAG (op, FLAG_DAMNED) 
  271.              /* Loophole bug? -FD- */ && !QUERY_FLAG (op, FLAG_UNPAID) )
  272.         {
  273.           if (op->nrof == 0)/* this is necessary for artifact sacrifices --FD-- */
  274.         count++;
  275.           else
  276.         count += op->nrof;
  277.         }
  278.     }
  279.     op=op->below;
  280.   }
  281.   return count;
  282. }
  283.  
  284. void eat_item(object *op,char *item)
  285. {
  286.   object *prev;
  287.  
  288.   prev = op;
  289.   op=op->below;
  290.   
  291.   while(op!=NULL) {
  292.     if (strcmp(op->arch->name,item)==0) {
  293.       decrease_ob_nr(op,op->nrof);
  294.       op=prev;
  295.     }
  296.     prev = op;
  297.     op=op->below;
  298.   }
  299. }
  300.  
  301. int check_sacrifice(object *op,object *improver)
  302. {
  303.   int count;
  304. #ifndef NEW_IMPROVE_WEAPON
  305.   if (check_item(op,"food")<5) {
  306.     new_draw_info(NDI_UNIQUE,0,op,"The gods want more food.");
  307.     return 0;
  308.   }
  309.   if (check_item(op,"booze")<10) {
  310.     new_draw_info(NDI_UNIQUE,0,op,"The gods want more booze.");
  311.     return 0;
  312.   }
  313. #endif
  314.   count = 0;
  315.   if (improver->slaying!=NULL) {
  316.     count = check_item(op,improver->slaying);
  317.     if (count<1) {
  318.       char buf[200];
  319.       sprintf(buf,"The gods want more %ss",improver->slaying);
  320.       new_draw_info(NDI_UNIQUE,0,op,buf);
  321.       return 0;
  322.     }
  323. #ifndef NEW_IMPROVE_WEAPON
  324.     eat_item(op,improver->slaying);
  325. #endif
  326.   }
  327.   else
  328.     count=1;
  329.  
  330. #ifndef NEW_IMPROVE_WEAPON
  331.   eat_item(op,"food");
  332.   eat_item(op,"booze");
  333. #endif
  334.   return count;
  335. }
  336.  
  337. int improve_weapon_stat(object *op,object *improver,object *weapon,
  338.             signed char *stat,int sacrifice_count,char *statname)
  339. {
  340.  
  341. #ifndef NEW_IMPROVE_WEAPON
  342.   if (sacrifice_count<2)
  343.     return 0;
  344.   sacrifice_count = isqrt(sacrifice_count/2);
  345. #endif
  346.   new_draw_info(NDI_UNIQUE,0,op,"Your sacrifice was accepted.");
  347.   *stat += sacrifice_count;
  348.   weapon->last_eat++;
  349.   new_draw_info_format(NDI_UNIQUE,0,op,
  350.     "Weapon's bonus to %s improved by %d",statname,sacrifice_count);
  351.   decrease_ob(improver);
  352.   /* So it updates the players stats and the window */
  353.   fix_player(op);
  354.   return 1;
  355. }
  356.  
  357. /* Types of improvements, hidden in the sp field. */
  358. #define IMPROVE_PREPARE 1
  359. #define IMPROVE_DAMAGE 2
  360. #define IMPROVE_WEIGHT 3
  361. #define IMPROVE_ENCHANT 4
  362. #define IMPROVE_STR 5
  363. #define IMPROVE_DEX 6
  364. #define IMPROVE_CON 7
  365. #define IMPROVE_WIS 8
  366. #define IMPROVE_CHA 9
  367. #define IMPROVE_INT 10
  368. #define IMPROVE_POW 11
  369.  
  370.  
  371. #ifndef NEW_IMPROVE_WEAPON
  372. /* build_weapon returns 0 if it was not able to work. */
  373. /* #### We are hiding extra information about the weapon in the level and
  374.    last_eat numbers for an object.  Hopefully this won't break anything ?? 
  375.    level == max improve last_eat == current improve*/
  376. int improve_weapon(object *op,object *improver,object *weapon)
  377. {
  378.   int sacrifice_count;
  379.   char *tmp;
  380.  
  381.   if(improver->stats.sp==IMPROVE_PREPARE) {
  382.     if (weapon->level!=0) {
  383.       new_draw_info(NDI_UNIQUE,0,op,"Weapon already prepared.");
  384.       return 0;
  385.     }
  386.     /* Could check for other things.  I'm assuming all things which provide
  387.        other benefits are also magic. */
  388.     if (weapon->magic!=0) {
  389.       new_draw_info(NDI_UNIQUE,0,op,"Cannot prepare magic weapons.");
  390.       return 0;
  391.     }
  392.     sacrifice_count=check_sacrifice(op,improver);
  393.     if (sacrifice_count<=0)
  394.       return 0;
  395.     sacrifice_count = isqrt(sacrifice_count);
  396.     weapon->level=sacrifice_count;
  397.     new_draw_info(NDI_UNIQUE,0,op,"Your sacrifice was accepted.");
  398.  
  399.     new_draw_info_format(NDI_UNIQUE, 0, op,"Your *%s may be improved %d times.",
  400.         weapon->name,sacrifice_count);
  401.  
  402.     tmp = (char *) malloc(strlen(weapon->name)+strlen(op->name) + 4);
  403.     sprintf(tmp,"%s's %s",op->name,weapon->name);
  404.     weapon->name=tmp;
  405.     weapon->nrof=0;  /*  prevents preparing n weapons in the same
  406.              slot at once! */
  407.     decrease_ob(improver);
  408.     weapon->last_eat=0;
  409.     return 1;
  410.   }
  411.   if (!(weapon->level>0)) {
  412.     new_draw_info(NDI_UNIQUE, 0,op,"This weapon has not been prepared.");
  413.     return 0;
  414.   }
  415.   if (weapon->level==weapon->last_eat) {
  416.     new_draw_info(NDI_UNIQUE, 0,op,"This weapon cannot be improved any more.");
  417.     return 0;
  418.   }
  419.     /* The skill system hands out wc and dam bonuses to fighters
  420.      * more generously than the old system (see fix_player). Thus
  421.      * we need to curtail the power of player enchanted weapons. 
  422.      * I changed this to 1 improvement per "fighter" level/5 -b.t. 
  423.      * Note:  Nothing should break by allowing this ratio to be different or
  424.      * using normal level - it is just a matter of play balance.
  425.      */
  426.   if (QUERY_FLAG(weapon, FLAG_APPLIED)) {
  427. #ifdef ALLOW_SKILLS
  428.       object *wc_obj=NULL;
  429.       int level=0;
  430.  
  431.       for(wc_obj=op->inv;wc_obj;wc_obj=wc_obj->below)
  432.     if(wc_obj->type==EXPERIENCE&&wc_obj->stats.Str) break;
  433.       if(!wc_obj) 
  434.     LOG(llevError,"Error: Player: %s lacks wc experience object\n",op->name);
  435.       else
  436.     level=wc_obj->level; 
  437.     if(weapon->last_eat>((level/5)+5)) {  
  438. #else
  439.     if(weapon->last_eat>(op->level+5)) {
  440. #endif
  441.     new_draw_info(NDI_UNIQUE, 0,op,"Improving the weapon will make it");
  442.     new_draw_info(NDI_UNIQUE, 0,op,"powerful to use.  Unready it if you");
  443.     new_draw_info(NDI_UNIQUE, 0,op,"really want to improve it.");
  444.     return 0;
  445.     }
  446.   }
  447.   sacrifice_count = check_sacrifice(op,improver);
  448.   if (sacrifice_count<=0)
  449.     return 0;
  450.   switch (improver->stats.sp) {
  451.    case IMPROVE_DAMAGE:
  452.     sacrifice_count = isqrt(sacrifice_count);
  453.     if ((sacrifice_count+weapon->stats.dam)>70)
  454.     sacrifice_count = 70 - weapon->stats.dam;
  455.     weapon->stats.dam += sacrifice_count;
  456.     weapon->weight += sacrifice_count*2000;
  457.     new_draw_info(NDI_UNIQUE, 0,op,"Your sacrifice was accepted.");
  458.     new_draw_info_format(NDI_UNIQUE, 0, op,
  459.     "Damage is increased by %d, weight by %6.1f kg",
  460.         sacrifice_count,(float)sacrifice_count*2.0);
  461.  
  462.     weapon->last_eat++;
  463.     decrease_ob(improver);
  464.     return 1;
  465.    case IMPROVE_WEIGHT:
  466.     sacrifice_count = isqrt(sacrifice_count)*750;
  467.     if (weapon->weight<sacrifice_count)
  468.       weapon->weight=1;
  469.     else
  470.       weapon->weight-=sacrifice_count;
  471.     new_draw_info(NDI_UNIQUE, 0,op,"Your sacrifice was accepted.");
  472.     new_draw_info_format(NDI_UNIQUE, 0, op,
  473.     "Weapon weight reduced by %6.1f kg to %6.1f kg",
  474.     (float)sacrifice_count/1000.0,(float)weapon->weight/1000.0);
  475.     weapon->last_eat++;
  476.     decrease_ob(improver);
  477.     return 1;
  478.    case IMPROVE_ENCHANT:
  479.     new_draw_info(NDI_UNIQUE, 0,op,"Your sacrifice was accepted.");
  480.     weapon->magic++;
  481.     weapon->last_eat++;
  482.     if (weapon->weight>1) weapon->weight=(weapon->weight*90)/100;
  483.  
  484.     new_draw_info_format(NDI_UNIQUE, 0, op
  485.     ,"Weapon magic increased to %d, weight lowered to %6.1f kg",
  486.     weapon->magic,(float)weapon->weight/1000.0);
  487.     decrease_ob(improver);
  488.     return 1;
  489.  
  490.    case IMPROVE_STR:
  491.     return improve_weapon_stat(op,improver,weapon,
  492.                                (signed char *) &(weapon->stats.Str),
  493.                    sacrifice_count,(char *) "strength");
  494.    case IMPROVE_DEX:
  495.     return improve_weapon_stat(op,improver,weapon,
  496.                                (signed char *) &(weapon->stats.Dex),
  497.                    sacrifice_count,(char *) "dexterity");
  498.    case IMPROVE_CON:
  499.     return improve_weapon_stat(op,improver,weapon,
  500.                                (signed char *) &(weapon->stats.Con),
  501.                    sacrifice_count,(char *) "constitution");
  502.    case IMPROVE_WIS:
  503.     return improve_weapon_stat(op,improver,weapon,
  504.                                (signed char *) &(weapon->stats.Wis),
  505.                    sacrifice_count,(char *) "wisdom");
  506.    case IMPROVE_CHA:
  507.     return improve_weapon_stat(op,improver,weapon,
  508.                                (signed char *) &(weapon->stats.Cha),
  509.                    sacrifice_count,(char *) "charisma");
  510.    case IMPROVE_INT:
  511.     return improve_weapon_stat(op,improver,weapon,
  512.                                (signed char *) &(weapon->stats.Int),
  513.                    sacrifice_count,(char *) "intelligence");
  514.    case IMPROVE_POW:
  515.     return improve_weapon_stat(op,improver,weapon,
  516.                                (signed char *) &(weapon->stats.Pow),
  517.                    sacrifice_count,(char *) "power");
  518.  
  519.    default:
  520.     new_draw_info(NDI_UNIQUE, 0,op,"Unknown improvement type.");
  521.     return 0;
  522.   }
  523. }
  524. #else
  525.  
  526. /* This does the prepare weapon scroll */
  527.  
  528. int prepare_weapon(object *op, object *improver, object *weapon)
  529. {
  530.     int sacrifice_count;
  531.     char *tmp;
  532.  
  533.     if (weapon->level!=0) {
  534.       new_draw_info(NDI_UNIQUE,0,op,"Weapon already prepared.");
  535.       return 0;
  536.     }
  537.     /* If someone wants to do a weapon that makes them vulnerable,
  538.      * let them.
  539.      */
  540.     if (weapon->immune || weapon->protected ||
  541.     weapon->stats.hp ||    /* regeneration */
  542.     weapon->stats.sp ||    /* sp regeneration */
  543.     weapon->stats.exp ||    /* speed */
  544.     weapon->stats.ac)    /* AC - only taifu's I think */
  545.     {
  546.       new_draw_info(NDI_UNIQUE,0,op,"Cannot prepare magic weapons.");
  547.       return 0;
  548.     }
  549.     sacrifice_count=check_sacrifice(op,improver);
  550.     if (sacrifice_count<=0)
  551.       return 0;
  552.     sacrifice_count = isqrt(sacrifice_count);
  553.     weapon->level=sacrifice_count;
  554.     new_draw_info(NDI_UNIQUE,0,op,"Your sacrifice was accepted.");
  555.     eat_item(op, improver->slaying);
  556.  
  557.     new_draw_info_format(NDI_UNIQUE, 0, op,"Your *%s may be improved %d times.",
  558.         weapon->name,sacrifice_count);
  559.  
  560.     tmp = (char *) malloc(strlen(weapon->name)+strlen(op->name) + 4);
  561.     sprintf(tmp,"%s's %s",op->name,weapon->name);
  562.     weapon->name=tmp; /* this seems to be wrong -Tero */
  563.     weapon->nrof=0;  /*  prevents preparing n weapons in the same
  564.              slot at once! */
  565.     decrease_ob(improver);
  566.     weapon->last_eat=0;
  567.     return 1;
  568. }
  569.  
  570.  
  571. /* this code is by b.t. (thomas@nomad.astro.psu.edu) -
  572.  * only 'enchantment' of armour is possible - improving
  573.  * the stats of a player w/ armour as well as a weapon
  574.  * will probably horribly unbalance the game. Magic enchanting
  575.  * depends on the level of the character - ie the plus
  576.  * value (magic) of the armour can never be increased beyond
  577.  * the level of the character / 10 -- rounding upish, nor may
  578.  * the armour value of the piece of equipment exceed either 
  579.  * the users level or 99)
  580.  */
  581.  
  582. int improve_armour(object *op, object *improver, object *armour)
  583. {
  584.     int addarm;
  585.  
  586.     addarm = armour->armour/25 + op->level/20 + 1;
  587.  
  588.     if (armour->magic>=(op->level/10+1) || ((armour->armour + 
  589.         addarm) >= op->level )) {
  590.         new_draw_info(NDI_UNIQUE, 0,op,"You are not yet powerfull enough");
  591.         new_draw_info(NDI_UNIQUE, 0,op,"to improve this armour.");
  592.         return 0;
  593.     }
  594.  
  595.     if( (armour->armour + addarm) <= 99)  {
  596.         armour->magic++;
  597.     armour->armour+=addarm;
  598.     armour->weight+=armour->weight*0.05;
  599.         decrease_ob(improver);
  600.         return 1;
  601.     } else {
  602.         armour->magic++;
  603.         new_draw_info(NDI_UNIQUE, 0,op,"The armour value of this equipment");
  604.         new_draw_info(NDI_UNIQUE, 0,op,"cannot be further improved.");
  605.         decrease_ob(improver);
  606.     return 1;
  607.     } 
  608.  
  609.  }
  610.  
  611. /* This is the new improve weapon code */
  612. /* build_weapon returns 0 if it was not able to work. */
  613. /* #### We are hiding extra information about the weapon in the level and
  614.    last_eat numbers for an object.  Hopefully this won't break anything ?? 
  615.    level == max improve last_eat == current improve*/
  616. int improve_weapon(object *op,object *improver,object *weapon)
  617. {
  618.   int sacrifice_count, sacrifice_needed=0;
  619.  
  620.   if(improver->stats.sp==IMPROVE_PREPARE) {
  621.     return prepare_weapon(op, improver, weapon);
  622.   }
  623.   if (weapon->level==0) {
  624.     new_draw_info(NDI_UNIQUE, 0,op,"This weapon has not been prepared.");
  625.     return 0;
  626.   }
  627.   if (weapon->level==weapon->last_eat) {
  628.     new_draw_info(NDI_UNIQUE, 0,op,"This weapon cannot be improved any more.");
  629.     return 0;
  630.   }
  631.   if (QUERY_FLAG(weapon, FLAG_APPLIED)) {
  632. #ifdef ALLOW_SKILLS
  633.       object *wc_obj=NULL;
  634.       int level=0;
  635.  
  636.       for(wc_obj=op->inv;wc_obj;wc_obj=wc_obj->below)
  637.     if(wc_obj->type==EXPERIENCE&&wc_obj->stats.Str) break;
  638.       if(!wc_obj) 
  639.     LOG(llevError,"Error: Player: %s lacks wc experience object\n",op->name);
  640.       else
  641.     level=wc_obj->level; 
  642.       if(weapon->last_eat>((level/5)+5)) {  
  643. #else
  644.       if(weapon->last_eat>(op->level+5)) {
  645. #endif
  646.     new_draw_info(NDI_UNIQUE, 0,op,"Improving the weapon will make it too");
  647.     new_draw_info(NDI_UNIQUE, 0,op,"powerful for you to use.  Unready it if you");
  648.     new_draw_info(NDI_UNIQUE, 0,op,"really want to improve it.");
  649.     return 0;
  650.     }
  651.   }
  652.   /* This just increases damage by 5 points, no matter what.  No sacrifice
  653.    * is needed.  Since stats.dam is now a 16 bit value and not 8 bit,
  654.    * don't put any maximum value on damage - the limit is how much the
  655.    * weapon  can be improved.
  656.    */
  657.   if (improver->stats.sp==IMPROVE_DAMAGE) {
  658.     weapon->stats.dam += 5;
  659.     weapon->weight += 5000;        /* 5 KG's */
  660.     new_draw_info_format(NDI_UNIQUE, 0, op,
  661.         "Damage has been increased by 5 to %d", weapon->stats.dam);
  662.     weapon->last_eat++;
  663.     decrease_ob(improver);
  664.     return 1;
  665.   }
  666.   if (improver->stats.sp == IMPROVE_WEIGHT) {
  667.     /* Reduce weight by 20% */
  668.     weapon->weight = (weapon->weight * 8)/10;
  669.     if (weapon->weight < 1) weapon->weight = 1;
  670.     new_draw_info_format(NDI_UNIQUE, 0, op,
  671.         "Weapon weight reduced to %6.1f kg",
  672.         (float)weapon->weight/1000.0);
  673.     weapon->last_eat++;
  674.     decrease_ob(improver);
  675.     return 1;
  676.   }
  677.   if (improver->stats.sp == IMPROVE_ENCHANT) {
  678.     weapon->magic++;
  679.     weapon->last_eat++;
  680.     new_draw_info_format(NDI_UNIQUE, 0, op
  681.         ,"Weapon magic increased to %d",weapon->magic);
  682.     decrease_ob(improver);
  683.     return 1;
  684.   }
  685.  
  686.   sacrifice_needed = weapon->stats.Str + weapon->stats.Int + weapon->stats.Dex+
  687.     weapon->stats.Pow + weapon->stats.Con + weapon->stats.Cha +
  688.     weapon->stats.Wis;
  689.  
  690.   if (sacrifice_needed<1)
  691.     sacrifice_needed =1;
  692.   sacrifice_needed *=2;
  693.  
  694.   sacrifice_count = check_sacrifice(op,improver);
  695.   if (sacrifice_count < sacrifice_needed) {
  696.     new_draw_info_format(NDI_UNIQUE, 0, op,
  697.         "You need at least %d %s", sacrifice_needed, improver->slaying);
  698.     return 0;
  699.   }
  700.   eat_item(op,improver->slaying);
  701.  
  702.   switch (improver->stats.sp) {
  703.    case IMPROVE_STR:
  704.     return improve_weapon_stat(op,improver,weapon,
  705.                                (signed char *) &(weapon->stats.Str),
  706.                    1,(char *) "strength");
  707.    case IMPROVE_DEX:
  708.     return improve_weapon_stat(op,improver,weapon,
  709.                                (signed char *) &(weapon->stats.Dex),
  710.                    1,(char *) "dexterity");
  711.    case IMPROVE_CON:
  712.     return improve_weapon_stat(op,improver,weapon,
  713.                                (signed char *) &(weapon->stats.Con),
  714.                    1,(char *) "constitution");
  715.    case IMPROVE_WIS:
  716.     return improve_weapon_stat(op,improver,weapon,
  717.                                (signed char *) &(weapon->stats.Wis),
  718.                    1,(char *) "wisdom");
  719.    case IMPROVE_CHA:
  720.     return improve_weapon_stat(op,improver,weapon,
  721.                                (signed char *) &(weapon->stats.Cha),
  722.                    1,(char *) "charisma");
  723.    case IMPROVE_INT:
  724.     return improve_weapon_stat(op,improver,weapon,
  725.                                (signed char *) &(weapon->stats.Int),
  726.                    1,(char *) "intelligence");
  727.    case IMPROVE_POW:
  728.     return improve_weapon_stat(op,improver,weapon,
  729.                                (signed char *) &(weapon->stats.Pow),
  730.                                1,(char *) "power");
  731.    default:
  732.     new_draw_info(NDI_UNIQUE, 0,op,"Unknown improvement type.");
  733.   }
  734.   LOG(llevError,"improve_weapon: Got to end of function\n");
  735.   return 0;
  736. }
  737. #endif
  738.  
  739. int check_improve_weapon (object *op, object *tmp)
  740. {
  741.     object *otmp;
  742.  
  743.     if(op->type!=PLAYER)
  744.       return 0;
  745.     if(QUERY_FLAG(tmp, FLAG_UNPAID)) {
  746.     new_draw_info(NDI_UNIQUE, 0,op,"You should pay for it first.");
  747.     return 0;
  748.     }
  749.     if (blocks_magic(op->map,op->x,op->y)) {
  750.     new_draw_info(NDI_UNIQUE, 0,op,"Something blocks the magic of the scroll.");
  751.     return 0;
  752.     }
  753.     if (op->inv==NULL) {
  754.       new_draw_info(NDI_UNIQUE, 0,op,"First item in inventory is not a weapon\n");
  755.       return 0;
  756.     }
  757.     for (otmp=op->inv; (otmp!=NULL && otmp->invisible); otmp=otmp->below) {
  758.     if (!otmp) {
  759.         new_draw_info(NDI_UNIQUE,0,op,"You have no weapon to enchant.\n");
  760.         return 0;
  761.     }
  762.     }
  763.     if (otmp->type!=WEAPON) {
  764.       new_draw_info(NDI_UNIQUE, 0,op,"First item in inventory is not a weapon\n");
  765.       return 0;
  766.     }
  767.     new_draw_info(NDI_UNIQUE, 0,op,"Applied weapon builder.");
  768.     improve_weapon(op,tmp,otmp);
  769.     if (op->contr->eric_server > 0)
  770.       esrv_send_item(op, tmp);
  771.     else
  772.       draw_inventory(op);
  773.     return 1;
  774. }
  775.  
  776. /* archetypes don't contain any MONEY_CHANGER object,
  777.  * so it this function really used/useful?
  778.  * Converters seems to make almost same.  -Tero
  779.  */
  780. void money_change(object *op,char *towhat)
  781. {
  782.   object *buying;
  783.   char buf[MAX_BUF];
  784.  
  785.   buying = get_archetype(towhat);
  786.  
  787.   if (buying==NULL) {
  788.     LOG(llevError,"Unable to find archetype %s\n",towhat);
  789.     return;
  790.   }
  791.   buying->nrof=100;
  792.   strncpy(buf,query_cost_string(buying,op,F_BUY),MAX_BUF);
  793.   if (pay_for_item(buying,op)) {
  794.     new_draw_info_format(NDI_UNIQUE, 0, op, 
  795.     "You paid %s for %s.",buf,query_name(buying));
  796.     (void) insert_ob_in_ob(buying,op);
  797.   } else {
  798.     new_draw_info_format(NDI_UNIQUE, 0, op, 
  799.     "You can't afford %s.",query_name(buying));
  800.     free_object(buying);
  801.   }
  802. }
  803.  
  804. /*
  805.  * convert_item() returns 1 if anything was converted, otherwise 0
  806.  */
  807. #define CONV_FROM(xyz)    xyz->slaying
  808. #define CONV_TO(xyz)    xyz->other_arch
  809. #define CONV_NR(xyz)    (unsigned char) xyz->stats.sp
  810. #define CONV_NEED(xyz)    (unsigned long) xyz->stats.food
  811.  
  812. int convert_item(object *item, object *converter) {
  813.   int nr=0;
  814.   object *tmp;
  815.   if(item->type==PLAYER||CONV_FROM(converter)!=item->arch->name||
  816.      (CONV_NEED(converter)&&CONV_NEED(converter)>item->nrof))
  817.     return 0;
  818.   if(CONV_NEED(converter)) {
  819.     nr=item->nrof/CONV_NEED(converter);
  820.     decrease_ob_nr(item,nr*CONV_NEED(converter));
  821.   } else {
  822.     remove_ob(item);
  823.     free_object(item);
  824.   }
  825.   item=arch_to_object(converter->other_arch);
  826.   if(CONV_NR(converter))
  827.     item->nrof=CONV_NR(converter);
  828.   if(nr)
  829.     item->nrof*=nr;
  830.   for(tmp=get_map_ob(converter->map,converter->x,converter->y);
  831.       tmp!=NULL;
  832.       tmp=tmp->above)
  833.     if(tmp->type==SHOP_FLOOR)
  834.       break;
  835.   if(tmp!=NULL)
  836.     SET_FLAG(item,FLAG_UNPAID);
  837.   item->x=converter->x;
  838.   item->y=converter->y;
  839.   insert_ob_in_map(item,converter->map);
  840.   return 1;
  841. }
  842.   
  843. /*
  844.  * Eneq(@csd.uu.se): Handle apply on containers. 
  845.  * Moved to own function and added many features [Tero.Haatanen@lut.fi]
  846.  */
  847. /* added the alchemical cauldron to the code -b.t. */
  848.  
  849. int apply_container (object *op, object *sack)
  850. {
  851.     char buf[MAX_BUF];
  852.     object *tmp;
  853.  
  854.     if(op->type!=PLAYER)
  855.     return 0; /* This might change */
  856.  
  857.     if (sack==NULL || sack->type != CONTAINER) {
  858.     LOG (llevError, "apply_container: %s is not container!\n",sack->name);
  859.     return 0;
  860.     }
  861.     op->contr->last_used = NULL;
  862.     op->contr->last_used_id = 0;
  863.  
  864.     if (sack->env!=op) {
  865.     if (sack->other_arch == NULL || sack->env != NULL) {
  866.         new_draw_info(NDI_UNIQUE, 0,op,"You must get it first.");
  867.         return 1;
  868.     }
  869.     /* It's on the ground, the problems begin */
  870.     if (op->container != sack) {
  871.         /* it's closed OR some player has opened it */
  872.         if (QUERY_FLAG(sack, FLAG_APPLIED)) {
  873.         for(tmp=get_map_ob(sack->map, sack->x, sack->y); 
  874.             tmp && tmp->container != sack; tmp=tmp->above);
  875.         if (tmp) {
  876.             /* some other player have opened it */
  877.             new_draw_info_format(NDI_UNIQUE, 0, op,
  878.             "%s is already occupied.", query_name(sack));
  879.             return 1;
  880.         }
  881.         }
  882.     }
  883.     if ( QUERY_FLAG(sack, FLAG_APPLIED)) {
  884.         if (op->container == NULL) {
  885.         tmp = arch_to_object (sack->other_arch);
  886.         /* not good, but insert_ob_in_ob() is too smart */
  887.         CLEAR_FLAG (tmp, FLAG_REMOVED);
  888.         tmp->x= tmp->y = tmp->ox = tmp->oy = 0;
  889.         tmp->map = NULL;
  890.         tmp->env = sack;
  891.         if (sack->inv)
  892.             sack->inv->above = tmp;
  893.         tmp->below = sack->inv;
  894.         tmp->above = NULL;
  895.         sack->inv = tmp;
  896.         SET_FLAG (sack, FLAG_WALK_OFF); /* trying force closing it */
  897.         SET_FLAG (sack, FLAG_FLY_OFF);
  898.         } else {
  899.         CLEAR_FLAG (sack, FLAG_WALK_OFF);
  900.         CLEAR_FLAG (sack, FLAG_FLY_OFF);
  901.         tmp = sack->inv;
  902.         if (tmp && tmp->type ==  CLOSE_CON) {
  903.             remove_ob(tmp);
  904.             free_object (tmp);
  905.         }
  906.         }
  907.     }
  908.     }
  909.  
  910.     if (QUERY_FLAG (sack, FLAG_APPLIED)) {
  911.     if (op->container) {
  912.         if (op->container != sack) {
  913.         tmp = op->container;
  914.         apply_container (op, tmp);
  915.         sprintf (buf, "You close %s and open ", query_name(tmp));
  916.         op->container = sack;
  917.         strcat (buf, query_name(sack));
  918.         strcat (buf, ".");
  919.         } else {
  920.         CLEAR_FLAG (sack, FLAG_APPLIED);
  921.         op->container = NULL;
  922.         sprintf (buf, "You close %s.", query_name(sack));
  923.         }
  924.     } else {
  925.         CLEAR_FLAG (sack, FLAG_APPLIED);
  926.         sprintf (buf, "You open %s.", query_name(sack));
  927.         SET_FLAG (sack, FLAG_APPLIED);
  928.         op->container = sack;
  929.     }
  930.     } else { /* not applied */
  931.     if (sack->slaying) { /* it's locked */
  932.         for (tmp=op->inv; tmp; tmp=tmp->below)
  933.         if (tmp->type == SPECIAL_KEY && 
  934.             tmp->slaying == sack->slaying)
  935.             break;
  936.         if (tmp) {
  937.         sprintf (buf, "You unlock %s with ", query_name(sack));
  938.         strcat (buf, query_name(tmp));
  939.         strcat (buf, ".");
  940.         SET_FLAG (sack, FLAG_APPLIED);
  941.         if (sack->env == NULL) { /* if it's on ground,open it also */
  942.             new_draw_info (NDI_UNIQUE,0,op, buf);
  943.             apply_container (op, sack);
  944.             return 1;
  945.         }
  946.         } else {
  947.         sprintf (buf, "You don't have the key to unlock %s.",
  948.              query_name(sack));
  949.         }
  950.     } else {
  951.         sprintf (buf, "You readied %s.", query_name(sack));
  952.         SET_FLAG (sack, FLAG_APPLIED);
  953.         if (sack->env == NULL) {  /* if it's on ground,open it also */
  954.         new_draw_info (NDI_UNIQUE, 0, op, buf);
  955.         apply_container (op, sack);
  956.         return 1;
  957.         }
  958.     }
  959.     }
  960.     new_draw_info (NDI_UNIQUE, 0, op, buf);
  961.     draw_inventory(op);
  962.     draw_all_look(op);
  963.     return 1;
  964. }
  965.  
  966. /*
  967.  * Eneq(@csd.uu.se): Handle apply on containers. 
  968.  * Moved to own function and added many features [Tero.Haatanen@lut.fi]
  969.  * This version is for client/server mode.
  970.  */
  971. int esrv_apply_container (object *op, object *sack)
  972. {
  973.     char buf[MAX_BUF];
  974.     object *tmp;
  975.  
  976.     if(op->type!=PLAYER)
  977.     return 0; /* This might change */
  978.  
  979.     if (sack==NULL || sack->type != CONTAINER) {
  980.     LOG (llevError, "esrv_apply_container: %s is not container!\n",sack->name);
  981.     return 0;
  982.     }
  983.  
  984.     if (sack->env != op) {
  985.     /* It's on the ground, the problems begin */
  986.     if (op->container != sack) {
  987.         /* it's closed OR some player has opened it */
  988.         if (QUERY_FLAG(sack, FLAG_APPLIED)) {
  989.         for(tmp=get_map_ob(sack->map, sack->x, sack->y); 
  990.             tmp && tmp->container != sack; tmp=tmp->above);
  991.         if (tmp) {
  992.             /* some other player have opened it */
  993.             new_draw_info_format(NDI_UNIQUE, 0, op,
  994.             "%s is already occupied.", query_name(sack));
  995.             return 1;
  996.         }
  997.         }
  998.     }
  999.     if ( QUERY_FLAG(sack, FLAG_APPLIED)) {
  1000.         if (op->container == NULL) {
  1001.         SET_FLAG (sack, FLAG_WALK_OFF); /* trying force closing it */
  1002.         SET_FLAG (sack, FLAG_FLY_OFF);
  1003.         } else {
  1004.         CLEAR_FLAG (sack, FLAG_WALK_OFF);
  1005.         CLEAR_FLAG (sack, FLAG_FLY_OFF);
  1006.         }
  1007.     }
  1008.     }
  1009.  
  1010.     if (QUERY_FLAG (sack, FLAG_APPLIED)) {
  1011.     if (op->container) {
  1012.         if (op->container != sack) {
  1013.         tmp = op->container;
  1014.         esrv_apply_container (op, tmp);
  1015.         sprintf (buf, "You close %s and open ", query_name(tmp));
  1016.         op->container = sack;
  1017.         strcat (buf, query_name(sack));
  1018.         strcat (buf, ".");
  1019.         esrv_send_item (op, sack);
  1020.         esrv_send_inventory (op, sack);
  1021.         } else {
  1022.         CLEAR_FLAG (sack, FLAG_APPLIED);
  1023.         op->container = NULL;
  1024.         sprintf (buf, "You close %s.", query_name(sack));
  1025.         esrv_send_item (op, sack);
  1026.         }
  1027.     } else {
  1028.         CLEAR_FLAG (sack, FLAG_APPLIED);
  1029.         sprintf (buf, "You open %s.", query_name(sack));
  1030.         SET_FLAG (sack, FLAG_APPLIED);
  1031.         op->container = sack;
  1032.         esrv_send_item (op, sack);
  1033.         esrv_send_inventory (op, sack);
  1034.     }
  1035.     } else { /* not applied */
  1036.     if (sack->slaying) { /* it's locked */
  1037.         for (tmp=op->inv; tmp; tmp=tmp->below)
  1038.         if (tmp->type == SPECIAL_KEY && 
  1039.             tmp->slaying == sack->slaying)
  1040.             break;
  1041.         if (tmp) {
  1042.         sprintf (buf, "You unlock %s with ", query_name(sack));
  1043.         strcat (buf, query_name(tmp));
  1044.         strcat (buf, ".");
  1045.         SET_FLAG (sack, FLAG_APPLIED);
  1046.         if (sack->env == NULL) { /* if it's on ground,open it also */
  1047.             new_draw_info(NDI_UNIQUE, 0, op, buf);
  1048.             esrv_apply_container (op, sack);
  1049.             return 1;
  1050.         } else {
  1051.             esrv_send_item (op, sack);
  1052.         }
  1053.         } else {
  1054.         sprintf (buf, "You don't have the key to unlock %s.",
  1055.              query_name(sack));
  1056.         }
  1057.     } else {
  1058.         sprintf (buf, "You readied %s.", query_name(sack));
  1059.         SET_FLAG (sack, FLAG_APPLIED);
  1060.         if (sack->env == NULL) {  /* if it's on ground,open it also */
  1061.         esrv_apply_container (op, sack);
  1062.         return 1;
  1063.         } else {
  1064.         esrv_send_item (op, sack);
  1065.         }
  1066.     }
  1067.     }
  1068.     new_draw_info(NDI_UNIQUE, 0, op, buf);
  1069.     return 1;
  1070. }
  1071.  
  1072. /*
  1073.  * Returns pointer a static string containing gravestone text
  1074.  */
  1075. char *gravestone_text (object *op)
  1076. {
  1077.     static char buf2[MAX_BUF];
  1078.     char buf[MAX_BUF];
  1079.     time_t now = time (NULL);
  1080.  
  1081.     strcpy (buf2, "                 R.I.P.\n\n");
  1082.     if (op->type == PLAYER)
  1083.     sprintf(buf, "%s the %s\n", op->name, op->contr->title);
  1084.     else
  1085.     sprintf(buf, "%s\n", op->name);
  1086.     strncat (buf2, "                    ",  20 - strlen(buf) / 2);
  1087.     strcat (buf2, buf);
  1088.     if (op->type == PLAYER)
  1089.     sprintf(buf, "who was in level %d when killed\n", op->level);
  1090.     else
  1091.     sprintf(buf, "who was in level %d when died.\n\n", op->level);
  1092.     strncat (buf2, "                    ",  20 - strlen(buf) / 2);
  1093.     strcat (buf2, buf);
  1094.     if (op->type == PLAYER) {
  1095.     sprintf(buf, "by %s.\n\n", op->contr->killer);
  1096.     strncat (buf2, "                    ",  21 - strlen(buf) / 2);
  1097.     strcat (buf2, buf);
  1098.     }
  1099.     strftime (buf, MAX_BUF, "%b %d %Y\n", localtime(&now));
  1100.     strncat (buf2, "                    ",  20 - strlen(buf) / 2);
  1101.     strcat (buf2, buf);
  1102.     return buf2;
  1103. }
  1104.  
  1105.  
  1106. int make_gravestone (object *op, object *grave)
  1107. {
  1108.     char buf[MAX_BUF];
  1109.     object *tmp, *stone = NULL, *corpse = NULL;
  1110.     
  1111.     for (tmp=get_map_ob(op->map, op->x, op->y); tmp; tmp=tmp->above)
  1112.     if (tmp->type == GRAVESTONE)
  1113.         stone = tmp;
  1114.     else if (tmp->type == CORPSE)
  1115.         corpse = tmp;
  1116.     for (tmp = op->inv; tmp; tmp = tmp->below)
  1117.     if (tmp->type == GRAVESTONE && !stone)
  1118.         stone = tmp;
  1119.     else if (tmp->type == CORPSE && !corpse)
  1120.         corpse = tmp;
  1121.     
  1122.     if (! stone) {
  1123.     new_draw_info(NDI_UNIQUE, 0,op, "You need a gravestone.");
  1124.     return 1;
  1125.     } else if (! corpse) {
  1126.     new_draw_info(NDI_UNIQUE, 0,op, "You need a corpse.");
  1127.     return 1;
  1128.     }
  1129.  
  1130.     /* make a gravestone */
  1131.     if(stone->name)
  1132.     free_string(stone->name);
  1133.     sprintf (buf, "%s's %s", corpse->name, stone->name);
  1134.     stone->name=add_string(buf);
  1135.     if (stone->msg)
  1136.     free_string(stone->msg);
  1137.     if (corpse->msg)
  1138.     stone->msg = add_string(corpse->msg);
  1139.     else
  1140.     stone->msg = add_string(gravestone_text(corpse));
  1141.     stone->x = op->x;
  1142.     stone->y = op->y;
  1143.     SET_FLAG (stone, FLAG_NO_PICK);
  1144.     remove_ob (stone);
  1145.     insert_ob_in_map(stone, op->map);
  1146.  
  1147.     /* delete grave and corpse */
  1148.     remove_ob (corpse);
  1149.     free_object (corpse);
  1150.     remove_ob (grave);
  1151.     free_object (grave);
  1152.     return 1;
  1153. }
  1154.  
  1155. /* apply returns 0 if it wasn't possible to apply that object */
  1156. /* op is the object that is causing object to be applied, tmp is the object
  1157.  * being applied.
  1158.  */
  1159.  
  1160. int apply(object *op, object *tmp) {
  1161.   char buf[MAX_BUF];
  1162.   int inven;
  1163.  
  1164.   if(tmp==NULL) {
  1165.     if(op!=NULL&&op->type==PLAYER)
  1166.       new_draw_info(NDI_UNIQUE, 0,op,"There is nothing to apply.");
  1167.     return 0;
  1168.   }
  1169.   inven=(tmp->env!=NULL);
  1170.   if(op->type==PLAYER&&!inven&&QUERY_FLAG(op,FLAG_FLYING)&&
  1171.     !QUERY_FLAG(tmp,FLAG_FLYING)&&!QUERY_FLAG(tmp,FLAG_FLY_ON)&&
  1172.      !QUERY_FLAG(op,FLAG_WIZ)) {
  1173.     new_draw_info(NDI_UNIQUE, 0,op,"But you are floating high above the ground!");
  1174.     return 0;
  1175.   }
  1176.   while(tmp!=NULL&&(!(QUERY_FLAG(tmp,FLAG_WALK_ON)||QUERY_FLAG(tmp,FLAG_FLY_ON))
  1177.     &&tmp->invisible))
  1178.     tmp=inven?tmp->below:tmp->above;
  1179.   if(tmp==NULL)
  1180.     return 0;
  1181.   if(QUERY_FLAG(tmp,FLAG_WAS_WIZ)&&!QUERY_FLAG(op,FLAG_WAS_WIZ)&&op->type==PLAYER) {
  1182. #ifdef SOUND_EFFECTS
  1183.     play_sound_map(op->map, op->x, op->y, SOUND_OB_EVAPORATE);
  1184. #endif
  1185.     new_draw_info(NDI_UNIQUE, 0,op,"The object disappears in a puff of smoke!");
  1186.     new_draw_info(NDI_UNIQUE, 0,op,"It must have been an illusion.");
  1187.     remove_ob(tmp);
  1188.     free_object(tmp);
  1189.     return 1;
  1190.   }
  1191.   if(op->type==PLAYER) {
  1192.     op->contr->last_used=tmp;
  1193.     op->contr->last_used_id=tmp->count;
  1194.   }
  1195.   switch(tmp->type) {
  1196.   case PLAYERMOVER:
  1197.     if (tmp->attacktype && (tmp->level || op->type!=PLAYER)) {
  1198.     if (!tmp->stats.maxsp) tmp->stats.maxsp=2.0;
  1199.     op->speed_left = -FABS(tmp->stats.maxsp*op->speed/tmp->speed);
  1200.     fprintf(stderr,"apply, playermove, player speed_left=%f\n", op->speed_left);
  1201.     }
  1202.     return 1;
  1203.  
  1204.   case SPINNER:
  1205.     if(op->direction) {
  1206.       op->direction=absdir(op->direction-tmp->stats.sp);
  1207.       update_turn_face(op);
  1208.     }
  1209.     return 1;
  1210.   case DIRECTOR:
  1211.     if(op->direction) {
  1212.       op->direction=tmp->stats.sp;
  1213.       update_turn_face(op);
  1214.     }
  1215.     return 1;
  1216.   case BUTTON:
  1217.   case PEDESTAL:
  1218.     update_button(tmp);
  1219.     return 1;
  1220.   case ALTAR:
  1221.     /* If it is a player that moved on top, just return.  A player can't
  1222.      * be the sacrifice.  This prevents double donation problems.
  1223.      */
  1224.     if (op->type==PLAYER) return 0;
  1225.  
  1226.     if (check_altar (tmp)) {
  1227.       /* Simple check.  Unfortunately, it means you can't cast magic bullet
  1228.        * with an altar.  We call it a Potion - altars are stationary - it
  1229.        * is up to map designers to use them properly.
  1230.        */
  1231.       if (tmp->stats.sp) {
  1232.         object *pl=get_map_ob(tmp->map, tmp->x, tmp->y);
  1233.     while (pl!=NULL && pl->type!=PLAYER)
  1234.         pl=pl->above;
  1235.     if (pl==NULL) {
  1236.         LOG(llevError,"Identify Altar: Can't find player!.\n");
  1237.         return 0;
  1238.     }
  1239.     cast_spell(pl, tmp, 0, tmp->stats.sp, 0, spellPotion, NULL);
  1240.     new_draw_info_format(NDI_BLACK, 0, op,
  1241.              "The altar casts %s.", spells[tmp->stats.sp].name);
  1242.       } else {
  1243.     tmp->value = 1;  /* works only once */
  1244.     push_button(tmp);
  1245.       }
  1246.     }
  1247.     return 1;
  1248.   case ARROW:
  1249.     if(QUERY_FLAG(op, FLAG_ALIVE)&&tmp->speed) {
  1250.       if(attack_ob(op,tmp)) {
  1251.     /* There can be cases where a monster 'kills' an arrow.  Typically
  1252.      * happens for things like black puddings that have hitback properties.
  1253.      */
  1254.     if (!QUERY_FLAG(tmp, FLAG_FREED)) {
  1255.         remove_ob(tmp);
  1256.         stop_arrow(tmp,op);
  1257.     }
  1258.       }
  1259.       return 1;
  1260.     }
  1261.     return 0;
  1262.   case CONE: /* A cone in the form of a wall */
  1263.     if(QUERY_FLAG(op, FLAG_ALIVE)&&tmp->speed)
  1264.       hit_player(op,tmp->stats.dam*20,tmp,tmp->attacktype);
  1265.     break;
  1266.   case FBULLET:
  1267.   case BULLET:
  1268.     check_fired_arch(tmp);
  1269.     return 1;
  1270.   case TRAPDOOR:
  1271. #ifdef SOUND_EFFECTS
  1272.     play_sound_map(op->map, op->x, op->y, SOUND_FALL_HOLE);
  1273. #endif
  1274.     {
  1275.       int max;
  1276.       object *ab;
  1277.       if(!tmp->value) {
  1278.         int tot;
  1279.         for(ab=tmp->above,tot=0;ab!=NULL;ab=ab->above)
  1280.           if(!QUERY_FLAG(ab,FLAG_FLYING))
  1281.             tot+=ab->weight+ab->carrying;
  1282.         if(!(tmp->value=(tot>tmp->weight)?1:0))
  1283.           return 1;
  1284.         tmp->face=&new_faces[tmp->arch->faces[tmp->value]];
  1285.         update_object(tmp);
  1286.       }
  1287.       for(ab=tmp->above,max=100;--max&&ab&&!QUERY_FLAG(ab, FLAG_FLYING);ab=ab->above) {
  1288.         transfer_ob(ab,(int)EXIT_X(tmp),(int)EXIT_Y(tmp));
  1289.         new_draw_info(NDI_UNIQUE, 0,ab,"You fall into a trapdoor!");
  1290.       }
  1291.     }
  1292.     return 1;
  1293.   case CONVERTER:
  1294.     if(convert_item(op,tmp))
  1295.       return 2;
  1296.     return 0;
  1297.   case HANDLE:
  1298.     new_draw_info(NDI_UNIQUE, 0,op,"You turn the handle.");
  1299. #ifdef SOUND_EFFECTS
  1300.     play_sound_map(op->map, op->x, op->y, SOUND_TURN_HANDLE);
  1301. #endif
  1302.     tmp->value=tmp->value?0:1;
  1303.     tmp->face=&new_faces[tmp->arch->faces[tmp->value]];
  1304.     update_object(tmp);
  1305.     push_button(tmp);
  1306.     return 1;
  1307.   case TRIGGER:
  1308.   case TRIGGER_BUTTON:
  1309.   case TRIGGER_PEDESTAL:
  1310.   case TRIGGER_ALTAR:
  1311.     check_trigger(tmp);
  1312.     return 1;
  1313.   case DEEP_SWAMP:
  1314.     deep_swamp(tmp, 1);
  1315.     return 1;
  1316.   case CHECK_INV:
  1317.     check_inv(op, tmp);
  1318.     break;
  1319.   case HOLE:
  1320.     if(tmp->stats.wc>0) /* Is the hole open? */
  1321.       return 1; /* Nope */
  1322.     {
  1323.     int i=find_free_spot(op->arch,op->map,EXIT_X(tmp),EXIT_Y(tmp),0,SIZEOFFREE);
  1324.       remove_ob(op);
  1325.       op->x=EXIT_X(tmp)+freearr_x[i],op->y=EXIT_Y(tmp)+freearr_y[i];
  1326.       insert_ob_in_map(op,op->map);
  1327.     }
  1328. #ifdef SOUND_EFFECTS
  1329.     play_sound_map(op->map, op->x, op->y, SOUND_FALL_HOLE);
  1330. #endif
  1331.     new_draw_info(NDI_UNIQUE, 0,op,"You fall through the hole!\n");
  1332.     return 1;
  1333.   case EXIT:
  1334.     if(op->type!=PLAYER)
  1335.       return 0;
  1336.     if(tmp->head!=NULL)
  1337.       tmp=tmp->head;
  1338.     if(!EXIT_PATH(tmp)) {
  1339.       new_draw_info_format(NDI_UNIQUE, 0, op, 
  1340.     "The %s is closed.",query_name(tmp));
  1341.       return 1;
  1342.     }
  1343.     if (tmp->msg)
  1344.     new_draw_info(NDI_NAVY, 0, op, tmp->msg);
  1345.     enter_exit(op,tmp);
  1346.     break;
  1347.   case ENCOUNTER:
  1348. #ifdef RANDOM_ENCOUNTERS
  1349.     random_encounter(op, tmp);
  1350. #endif
  1351.     break;
  1352.   case SHOP_MAT:
  1353.     {
  1354.       SET_FLAG(op,FLAG_NO_APPLY);
  1355.       if(op->type!=PLAYER) {
  1356.         if(QUERY_FLAG(op, FLAG_UNPAID)) { /* Just move the item to an adjacent place */
  1357.           int i=find_free_spot(op->arch,op->map,op->x,op->y,1,9);
  1358.           if(!i) return 1;
  1359.           transfer_ob(op,op->x+freearr_x[i],op->y+freearr_y[i]);
  1360.           CLEAR_FLAG(op, FLAG_NO_APPLY);
  1361.           return 1;
  1362.         }
  1363.         if(op->more||op->head) return 1; /* Some nasty bug has to be fixed here... */
  1364.         teleport(tmp,SHOP_MAT);
  1365.         CLEAR_FLAG(op, FLAG_NO_APPLY);
  1366.         return 1;
  1367.       }
  1368.       if(get_payment(op)) {
  1369.         teleport(tmp,SHOP_MAT);
  1370.         if((tmp=get_map_ob(op->map,op->x,op->y))==NULL||tmp->type!=SHOP_FLOOR)
  1371.           new_draw_info(NDI_UNIQUE, 0,op,"Thank you for visiting our shop.");
  1372.       }
  1373.       else {
  1374.         int i=find_free_spot(op->arch,op->map,op->x,op->y,1,9);
  1375.         if(!i)
  1376.           LOG(llevError,"Internal shop-mat problem.\n");
  1377.         else {
  1378.           remove_ob(op);
  1379.           op->x+=freearr_x[i],op->y+=freearr_y[i];
  1380.           insert_ob_in_map(op,op->map);
  1381.         }
  1382.       }
  1383.       CLEAR_FLAG(op, FLAG_NO_APPLY);
  1384.       return 1;
  1385.     }
  1386.   case SIGN:
  1387.     if(tmp->msg==NULL)
  1388.       new_draw_info(NDI_UNIQUE, 0,op,"Nothing is written on it.");
  1389.     else
  1390.       new_draw_info(NDI_UNIQUE | NDI_NAVY,0, op,tmp->msg);
  1391.     return 1;
  1392.   case BOOK: 
  1393.     if(op->type!=PLAYER) return 1;
  1394.     if(QUERY_FLAG(tmp,FLAG_UNPAID)) {
  1395.       new_draw_info(NDI_UNIQUE, 0,op,"You should pay for it first.");
  1396.       break;
  1397.     }
  1398.     if(tmp->msg==NULL) {
  1399.       new_draw_info_format(NDI_UNIQUE, 0, op, 
  1400.     "You open the %s and find it empty.", tmp->name);
  1401.     } else 
  1402. #ifdef ALLOW_SKILLS /* need a literacy skill to read stuff! */
  1403.     if(!QUERY_FLAG(op,FLAG_WIZ)&&!change_skill(op,SK_LITERACY)) 
  1404.       new_draw_info(NDI_UNIQUE, 0,op,
  1405.     "You are unable to decipher the strange symbols.");
  1406.     else if(QUERY_FLAG(op,FLAG_WIZ)||((SK_level(op)+5)>=tmp->level)) 
  1407. #endif
  1408.     {
  1409.       new_draw_info_format(NDI_UNIQUE, 0, op, 
  1410.     "You open the %s and start reading.", tmp->name);
  1411.       new_draw_info(NDI_UNIQUE | NDI_NAVY, 0, op, 
  1412.     tmp->msg);
  1413. #ifdef ALLOW_SKILLS /* gain xp from reading */  
  1414.       if(!QUERY_FLAG(tmp,FLAG_NO_SKILL_IDENT)) { /* only if not read before */ 
  1415.       int exp_gain=calc_skill_exp(op,tmp);
  1416.       if(!QUERY_FLAG(tmp,FLAG_IDENTIFIED)) {
  1417.         /*exp_gain *= 2; because they just identified it too */
  1418.         SET_FLAG(tmp,FLAG_IDENTIFIED);
  1419.         if(tmp->env) draw_inventory(op);
  1420.         else draw_look(op);
  1421.       }
  1422.           add_exp(op,exp_gain);
  1423.           SET_FLAG(tmp,FLAG_NO_SKILL_IDENT); /* so no more xp gained from this book */ 
  1424.       }   
  1425.     } else { 
  1426.       new_draw_info(NDI_UNIQUE, 0,op,"This book is too difficult for you to read.");
  1427. #endif
  1428.     }
  1429.     return 1;
  1430.  
  1431. /* these scrolls allow acquistion of skills by players
  1432.  * -b.t. thomas@nomad.astro.psu.edu
  1433.  */
  1434.   case SKILLSCROLL: 
  1435. #ifdef ALLOW_SKILLS /* calls here shouldnt happen, but to be on safe side put here */ 
  1436.     if(op->type!=PLAYER)
  1437.       return 0;
  1438.     if(QUERY_FLAG(tmp,FLAG_UNPAID)) {
  1439.       new_draw_info(NDI_UNIQUE, 0,op,"You should pay for it first.");
  1440.       break;
  1441.     }
  1442.     switch((int)learn_skill(op,tmp)) {
  1443.       case 0:
  1444.             new_draw_info(NDI_UNIQUE, 0,op,"You already possess the knowledge "); 
  1445.             new_draw_info_format(NDI_UNIQUE, 0,op,"held within the %s.\n",query_name(tmp)); 
  1446.       return 1;
  1447.       case 1: 
  1448.             new_draw_info_format(NDI_UNIQUE, 0,op,"You succeed in learning %s",
  1449.         skills[tmp->stats.sp].name);
  1450.             new_draw_info_format(NDI_UNIQUE, 0, op,
  1451.              "Type 'bind ready_skill %s",skills[tmp->stats.sp].name);
  1452.           new_draw_info(NDI_UNIQUE, 0,op,"to store the skill in a key.");
  1453.       fix_player(op); /* to immediately link new skill to exp object */
  1454.             break;
  1455.       default:
  1456.             new_draw_info_format(NDI_UNIQUE,0,op,
  1457.         "You fail to learn the knowledge of the %s.\n",query_name(tmp));
  1458.       break;
  1459.     }
  1460.     decrease_ob(tmp);
  1461.     draw_inventory(op);
  1462. #endif
  1463.     return 1; 
  1464.   case SPELLBOOK:
  1465.     if(op->type!=PLAYER)
  1466.       return 0;
  1467.     if(QUERY_FLAG(tmp,FLAG_UNPAID)) {
  1468.       new_draw_info(NDI_UNIQUE, 0,op,"You should pay for it first.");
  1469.       break;
  1470.     }
  1471.  
  1472.     /* artifact_spellbooks have 'slaying' field point to a spell name,
  1473.     ** instead of having their spell stored in stats.sp.  We should update
  1474.     ** stats->sp to point to that spell */
  1475.  
  1476.     if(tmp->slaying != NULL) {
  1477.        if((tmp->stats.sp = look_up_spell_name(tmp->slaying)) <0 ){
  1478.       tmp->stats.sp = -1; 
  1479.       new_draw_info_format(NDI_UNIQUE, 0, op,
  1480.         "The book's formula for %s is incomplete", tmp->slaying);
  1481.       return 1;
  1482.        }
  1483.        /* now clear tmp->slaying since we no longer need it */
  1484.        free_string(tmp->slaying);
  1485.        tmp->slaying=NULL;
  1486.     }
  1487.  
  1488.     /* need a literacy skill to learn spells. Also, having a literacy level
  1489.      * lower than the spell will make learning the spell more difficult */
  1490. #ifdef ALLOW_SKILLS 
  1491.     if(op->type==PLAYER&&!change_skill(op,SK_LITERACY)) {
  1492.       new_draw_info(NDI_UNIQUE, 0,op,"You can't read! Your attempt fails.");
  1493.       return 1;
  1494.     }
  1495. #endif
  1496.     if(tmp->stats.sp < 0 || tmp->stats.sp > NROFREALSPELLS
  1497.         || spells[tmp->stats.sp].level>(SK_level(op)+10)) {
  1498.       new_draw_info(NDI_UNIQUE, 0,op,"You are unable to decipher the strange symbols.");
  1499.       return 1;
  1500.     } 
  1501.  
  1502.     new_draw_info_format(NDI_UNIQUE, 0, op, 
  1503.     "The spellbook contains the %s level spell %s.",
  1504.             get_levelnumber(spells[tmp->stats.sp].level),
  1505.             spells[tmp->stats.sp].name);
  1506.     if(check_spell_known(op,tmp->stats.sp)) {
  1507.       new_draw_info(NDI_UNIQUE, 0,op,"You already know that spell.\n");
  1508.  
  1509.       if (!QUERY_FLAG(tmp, FLAG_IDENTIFIED)) {
  1510.     identify(tmp);
  1511.     if (op->contr->eric_server > 0)
  1512.       esrv_send_item(op, tmp);
  1513.     else if (tmp->env)
  1514.       draw_inventory(op);
  1515.     else
  1516.       draw_look(op);
  1517.       }
  1518.       return 1;
  1519.     }
  1520.     /* I changed spell learning in 2 ways:
  1521.      *
  1522.      *  1- MU spells use Int to learn, Cleric spells use Wisdom
  1523.      *
  1524.      *  2- The learner's level (in skills sytem level==literacy level; if no 
  1525.      *     skills level == overall level) impacts the chances of spell learning. 
  1526.      *
  1527.      * Overall, chances are the same but a player will find having a high 
  1528.      * literacy rate very useful!  -b.t. 
  1529.      */ 
  1530.     if(QUERY_FLAG(tmp,FLAG_STARTEQUIP) || RANDOM()%150-(2*SK_level(op)) <
  1531.     learn_spell[spells[tmp->stats.sp].cleric ? op->stats.Wis : op->stats.Int]) {
  1532. #ifdef SOUND_EFFECTS
  1533.       play_sound_player_only(op->contr, SOUND_LEARN_SPELL);
  1534. #endif
  1535.       new_draw_info(NDI_UNIQUE, 0,op,"You succeed in learning the spell!");
  1536.       op->contr->known_spells[op->contr->nrofknownspells++]=tmp->stats.sp;
  1537.       if(op->contr->nrofknownspells == 1)
  1538.     op->contr->chosen_spell=tmp->stats.sp;
  1539.       new_draw_info_format(NDI_UNIQUE, 0, op, 
  1540.     "Type 'bind cast %s",spells[tmp->stats.sp].name);
  1541.       new_draw_info(NDI_UNIQUE, 0,op,"to store the spell in a key.");
  1542. #ifdef ALLOW_SKILLS /* xp gain to literacy for spell learning */
  1543.       if(op->type==PLAYER) add_exp(op,calc_skill_exp(op,tmp));
  1544. #endif
  1545.     } else {
  1546. #ifdef SOUND_EFFECTS
  1547.       play_sound_player_only(op->contr, SOUND_FUMBLE_SPELL);
  1548. #endif
  1549.       new_draw_info(NDI_UNIQUE, 0,op,"You fail to learn the spell.\n");
  1550.     }
  1551.     remove_ob(tmp);
  1552.     free_object(tmp);
  1553.     return 1;
  1554.   case SCROLL: {
  1555.       int scroll_spell=tmp->stats.sp, old_spell=0;
  1556.       rangetype old_shoot=range_none;
  1557.  
  1558.     if(QUERY_FLAG(tmp, FLAG_UNPAID)) {
  1559.       new_draw_info(NDI_UNIQUE, 0,op,"You should pay for it first.");
  1560.       break;
  1561.     }
  1562.     if (!QUERY_FLAG(tmp, FLAG_IDENTIFIED)) 
  1563.       identify(tmp);
  1564.  
  1565.     if( scroll_spell < 0 || scroll_spell >= NROFREALSPELLS) {
  1566.         sprintf(buf, "The scroll just doesn't make sense!");
  1567.         break;
  1568.     }    
  1569.  
  1570.     if(op->type==PLAYER) {
  1571. #ifdef ALLOW_SKILLS /* players need a literacy skill to read stuff! */
  1572.     int exp_gain=0;
  1573.  
  1574.         if(!QUERY_FLAG(op,FLAG_WIZ)&&!change_skill(op,SK_LITERACY)){ 
  1575.           new_draw_info(NDI_UNIQUE, 0,op,
  1576.             "You are unable to decipher the strange symbols.");
  1577.           break;
  1578.         } 
  1579.     /* ok, they can read, but did they fumble the formula? */
  1580.         if(!QUERY_FLAG(op,FLAG_WIZ)&&
  1581.             RANDOM()%(SK_level(op)+get_weighted_skill_stat_sum(op,SK_LITERACY))<tmp->level) 
  1582.     { 
  1583.             new_draw_info(NDI_UNIQUE,0,op,"You flub the wording of the scroll!"); 
  1584.         if(tmp->level<(5+RANDOM()%10)) { /* goofed it */
  1585.                 new_draw_info(NDI_UNIQUE,0,op,"The magic of the scroll is ruined!");
  1586.                decrease_ob(tmp);
  1587.         draw_inventory(op);
  1588.         return 0;
  1589.         }
  1590. #ifdef SPELL_FAILURE_EFFECTS
  1591.             else if(RANDOM()%3) /* something quite bad */
  1592.                 spell_failure(op,(-5*RANDOM()%(tmp->level+1))-1,spells[scroll_spell].sp);
  1593. #endif /* SPELL_FAILURE */ 
  1594.         else { /* something bad */
  1595.                 new_draw_info(NDI_UNIQUE,0,op,"The magic of the scroll warps randomly!");
  1596.             scroll_spell = SP_WOW;
  1597.         }
  1598.     } 
  1599.     else if((exp_gain = calc_skill_exp(op,tmp)))
  1600.         add_exp(op,exp_gain); /* all ok, give the player xp for reading */
  1601.  
  1602.         /* Now, call here so the right skill is readied -- literacy 
  1603.      * isnt necesarily connected to the exp obj to which the xp 
  1604.      * will go (for kills made by the magic of the scroll) 
  1605.      */ 
  1606.         SET_FLAG(tmp,FLAG_APPLIED);
  1607.         (void) check_skill_to_apply(op,tmp);
  1608.         CLEAR_FLAG(tmp,FLAG_APPLIED);
  1609.  
  1610. #endif/* ALLOW_SKILLS */ 
  1611.         old_shoot= op->contr->shoottype;
  1612.         old_spell = op->contr->chosen_spell;
  1613.         op->contr->shoottype=range_scroll;
  1614.         op->contr->chosen_spell = scroll_spell;
  1615.     }
  1616.  
  1617.     new_draw_info_format(NDI_BLACK, 0, op,
  1618.         "The scroll of %s turns to dust.", spells[tmp->stats.sp].name);
  1619.     new_draw_info_format(NDI_ALL, 6, op,
  1620.         "%s reads a scroll of %s.",op->name,spells[tmp->stats.sp].name);
  1621.  
  1622.     cast_spell(op,tmp,0,scroll_spell,0,spellScroll,NULL);
  1623.     decrease_ob(tmp);
  1624.     if(op->type==PLAYER) {
  1625.       if(op->contr->golem==NULL) {
  1626.         op->contr->shoottype=old_shoot;
  1627.     op->contr->chosen_spell = old_spell;
  1628.       }
  1629.       draw_stats(op);
  1630.     }
  1631.     break;
  1632.   }
  1633.   case POTION:
  1634.     SET_FLAG(tmp,FLAG_APPLIED);
  1635.     (void) check_skill_to_apply(op,tmp);
  1636.     CLEAR_FLAG(tmp,FLAG_APPLIED);
  1637.     return apply_potion(op, tmp);
  1638.  
  1639.  
  1640. /* Eneq(@csd.uu.se): Handle apply on containers. */
  1641.   case CLOSE_CON:
  1642.     if (op->contr->eric_server > 0)
  1643.       return esrv_apply_container (op, tmp->env);
  1644.     else
  1645.       return apply_container (op, tmp->env);
  1646.   case CONTAINER:
  1647.     if (op->contr->eric_server > 0)
  1648.       return esrv_apply_container (op, tmp);
  1649.     else
  1650.       return apply_container (op, tmp);
  1651.  
  1652.   case TREASURE: {
  1653.     object *treas;
  1654.     if(QUERY_FLAG(tmp, FLAG_UNPAID)) {
  1655.       new_draw_info(NDI_UNIQUE, 0,op,"You should pay for it first.");
  1656.       break;
  1657.     }
  1658. /*  Nice side effect of new treasure creation method is that the treasure
  1659.     for the chest is done when the chest is created, and put into the chest
  1660.     inventory.  So that when the chest burns up, the items still exist.  Also
  1661.     prevents people fromt moving chests to more difficult maps to get better
  1662.     treasure
  1663. */
  1664.     treas = tmp->inv;
  1665.     if(treas==NULL) {
  1666.       new_draw_info(NDI_UNIQUE, 0,op,"The chest was empty.");
  1667.       decrease_ob(tmp);
  1668.       return 1;
  1669.     }
  1670.     do {
  1671.       remove_ob(treas);
  1672.       draw_find(op,treas);
  1673.       treas->x=op->x,treas->y=op->y;
  1674.  
  1675.       /* Changed (0.91.2) - always drop treasure to floor (needed for
  1676.        * trap code
  1677.        */
  1678.       insert_ob_in_map(treas,op->map);
  1679.     } while ((treas=tmp->inv)!=NULL);
  1680.     
  1681.     decrease_ob(tmp);
  1682.  
  1683.     /* Done to re-stack map with player on top? */
  1684.     remove_ob(op);
  1685.     insert_ob_in_map(op,op->map);
  1686.     break;
  1687.   }
  1688.   case WAND:
  1689.     if(apply_special(op,tmp))
  1690.       return 1;
  1691.     if(op->type==PLAYER) {
  1692.       if(QUERY_FLAG(tmp, FLAG_APPLIED)) {
  1693.         op->contr->shoottype=range_wand;
  1694.     op->contr->chosen_item_spell= tmp->stats.sp;
  1695.         if (QUERY_FLAG(tmp,FLAG_BEEN_APPLIED) || QUERY_FLAG(tmp, FLAG_IDENTIFIED))
  1696.           op->contr->known_spell = 1;
  1697.         else
  1698.           op->contr->known_spell = 0;
  1699.         fix_player(op);
  1700.       }
  1701.     } else {
  1702.       if(QUERY_FLAG(tmp, FLAG_APPLIED))
  1703.     SET_FLAG(op, FLAG_READY_WAND);
  1704.       else
  1705.     CLEAR_FLAG(op, FLAG_READY_WAND);
  1706.     }
  1707.     return 1;
  1708.   case ROD:
  1709.     if(apply_special(op,tmp))
  1710.       return 1;
  1711.     if(op->type==PLAYER) {
  1712.       if(QUERY_FLAG(tmp, FLAG_APPLIED)) {
  1713.         op->contr->shoottype=range_rod;
  1714.         op->contr->chosen_item_spell=tmp->stats.sp;
  1715.         if (QUERY_FLAG(tmp, FLAG_BEEN_APPLIED) || QUERY_FLAG(tmp, FLAG_IDENTIFIED))
  1716.           op->contr->known_spell = 1;
  1717.         else
  1718.           op->contr->known_spell = 0;
  1719.         fix_player(op);
  1720.       }
  1721.     } else {
  1722.       if(QUERY_FLAG(tmp, FLAG_APPLIED))
  1723.     SET_FLAG(op, FLAG_READY_ROD);
  1724.       else
  1725.     CLEAR_FLAG(op, FLAG_READY_ROD);
  1726.     }
  1727.     return 1;
  1728.   case HORN:
  1729.     if(apply_special(op,tmp))
  1730.       return 1;
  1731.     if(op->type==PLAYER) {
  1732.       if(QUERY_FLAG(tmp, FLAG_APPLIED)) {
  1733.         op->contr->shoottype=range_horn;
  1734.         op->contr->chosen_item_spell=tmp->stats.sp;
  1735.         if (QUERY_FLAG(tmp, FLAG_BEEN_APPLIED) || QUERY_FLAG(tmp, FLAG_IDENTIFIED))
  1736.           op->contr->known_spell = 1;
  1737.         else
  1738.           op->contr->known_spell = 0;
  1739.         fix_player(op);
  1740.       }
  1741.     } else {
  1742.       if(QUERY_FLAG(tmp, FLAG_APPLIED))
  1743.     SET_FLAG(op, FLAG_READY_HORN);
  1744.       else
  1745.     CLEAR_FLAG(op, FLAG_READY_HORN);
  1746.     }
  1747.     return 1;
  1748.   case BOW:
  1749.     if(apply_special(op,tmp))
  1750.       return 0;
  1751.     if(QUERY_FLAG(tmp, FLAG_APPLIED)) {
  1752.       new_draw_info_format(NDI_UNIQUE, 0, op,
  1753.     "You will now fire %s with %s.",
  1754.           tmp->race ? tmp->race : "nothing", query_name(tmp));
  1755.       if(op->type==PLAYER) {
  1756.         op->contr->shoottype=range_bow;
  1757.         fix_player(op);
  1758.       }
  1759.     }
  1760.     return 1;
  1761. #ifdef ALLOW_SKILLS
  1762.   case SKILL:   /* allows skill tools  to be used -b.t */
  1763.     if(apply_special(op,tmp))
  1764.       return 0;
  1765.     if(!tmp->invisible&&QUERY_FLAG(tmp, FLAG_APPLIED)) {
  1766.         SET_FLAG(op, FLAG_READY_SKILL);
  1767.         op->chosen_skill=tmp;
  1768.         if(op->type==PLAYER) {
  1769.           new_draw_info_format(NDI_UNIQUE, 0, op,
  1770.              "You can now use the skill: %s.",skills[tmp->stats.sp].name);
  1771.           op->contr->shoottype=range_skill;
  1772.       link_player_skill(op, tmp);
  1773.           fix_player(op);
  1774.           draw_stats(op);
  1775.         }
  1776.     } else { 
  1777.         CLEAR_FLAG(op, FLAG_READY_SKILL);
  1778.     unlink_skill(tmp);
  1779.     }
  1780.     return 1;
  1781. #endif
  1782.   case WEAPON:
  1783.   case ARMOUR:
  1784.   case BOOTS:
  1785.   case GLOVES:
  1786.   case AMULET:
  1787.   case GIRDLE:
  1788.   case BRACERS:
  1789.   case SHIELD:
  1790.   case HELMET:
  1791.   case RING:
  1792.   case CLOAK:
  1793. /* Mol(mol@meryl.csd.uu.se) compressed return & apply_s into one statement */
  1794. /* Frank: If done this way, a ! must be prepended */
  1795.     return !apply_special(op,tmp);
  1796.   case DRINK:
  1797.   case FOOD:
  1798.   case FLESH:
  1799.     if(QUERY_FLAG(tmp, FLAG_UNPAID)) {
  1800.       new_draw_info(NDI_UNIQUE, 0,op,"You should pay for it first.");
  1801.       return 1;
  1802.     }
  1803.     if(op->type!=PLAYER)
  1804.       op->stats.hp=op->stats.maxhp;
  1805.     else {
  1806.       if(op->stats.food+tmp->stats.food>999) {
  1807.     if(tmp->type==FOOD || tmp->type==FLESH)
  1808.       new_draw_info(NDI_UNIQUE, 0,op,"You can't possibly eat all that now.");
  1809.     else
  1810.       new_draw_info(NDI_UNIQUE, 0,op,"You can't possibly drink all that now.");
  1811.     return 1;
  1812.       }
  1813.       if(!QUERY_FLAG(tmp, FLAG_CURSED)) {
  1814.         char buf[MAX_BUF];
  1815.         if(tmp->type==DRINK)
  1816.             sprintf(buf,"Ahhh...that %s tasted good.",tmp->name);
  1817.         else 
  1818.             sprintf(buf,"The %s tasted %s",tmp->name,
  1819.         tmp->type==FLESH?"terrible!":"good.");
  1820.  
  1821.         new_draw_info(NDI_UNIQUE, 0,op,buf); 
  1822.         op->stats.food+=tmp->stats.food;
  1823.         op->stats.hp+=tmp->stats.food/50;
  1824.         if(op->stats.hp>op->stats.maxhp)
  1825.           op->stats.hp=op->stats.maxhp;
  1826.       }
  1827.       /* special food hack -b.t. */
  1828.       if(tmp->title || QUERY_FLAG(tmp,FLAG_CURSED)) eat_special_food(op,tmp);
  1829.       draw_stats(op);
  1830.     }
  1831.     decrease_ob(tmp);
  1832.     return 1;
  1833.   case POISON:
  1834.     if(op->type!=PLAYER)
  1835.       return 0;
  1836.     if(QUERY_FLAG(tmp, FLAG_UNPAID)) {
  1837.       new_draw_info(NDI_UNIQUE, 0,op,"You should pay for it first.");
  1838.       return 1;
  1839.     }
  1840. #ifdef SOUND_EFFECTS
  1841.     play_sound_player_only(op->contr, SOUND_DRINK_POISON);
  1842. #endif
  1843.     new_draw_info(NDI_UNIQUE, 0,op,"Yech!  That tasted poisonous!");
  1844.     strcpy(op->contr->killer,"poisonous booze");
  1845.     op->stats.hp+=tmp->stats.hp;
  1846.     op->stats.food-=op->stats.food/4;
  1847.     draw_stats(op);
  1848.     decrease_ob(tmp);
  1849.     return 1;
  1850.   case SAVEBED:
  1851.     if(op->type!=PLAYER)
  1852.       return 0;
  1853.     if(!op->contr->name_changed||!op->stats.exp) {
  1854.       new_draw_info(NDI_UNIQUE, 0,op,"You don't deserve to save your character yet.");
  1855.       return 1;
  1856.     }
  1857.     if(QUERY_FLAG(op,FLAG_WAS_WIZ)) {
  1858.       new_draw_info(NDI_UNIQUE, 0,op,"Since you have cheated you can't save.");
  1859.       return 1;
  1860.     }
  1861.     remove_ob(op);
  1862.     op->direction=0;
  1863.     op->contr->count_left=0;
  1864.     new_draw_info_format(NDI_UNIQUE | NDI_ALL, 5, op,
  1865.     "%s leaves the game.",op->name);
  1866.  
  1867.     strcpy(op->contr->killer,"left");
  1868.     check_score(op); /* Always check score */
  1869.     (void)save_player(op,0);
  1870.     play_again(op);
  1871.     op->map->players--;
  1872. #if MAP_MAXTIMEOUT 
  1873.     op->map->timeout = MAP_TIMEOUT(op->map);
  1874. #endif
  1875.     return 1;
  1876.  
  1877.    case ARMOUR_IMPROVER:
  1878.     if(op->type!=PLAYER)
  1879.       return 0;
  1880.     if(QUERY_FLAG(tmp, FLAG_UNPAID)) {
  1881.         new_draw_info(NDI_UNIQUE, 0,op,"You should pay for it first.");
  1882.         return 0;
  1883.     }
  1884.     if (blocks_magic(op->map,op->x,op->y)) {
  1885.         new_draw_info(NDI_UNIQUE, 0,op,"Something blocks the magic of the scroll.");
  1886.         return 0;
  1887.     }
  1888.     if (op->inv==NULL)  
  1889.             return 0;
  1890.  
  1891.     if (op->inv->type==ARMOUR
  1892.     || op->inv->type==CLOAK
  1893.     || op->inv->type==BOOTS || op->inv->type==GLOVES
  1894.     ||op->inv->type==BRACERS || op->inv->type==SHIELD
  1895.     ||op->inv->type==HELMET
  1896.     ) {
  1897.             new_draw_info(NDI_UNIQUE, 0,op,"Applying armour enchantment.");
  1898.             improve_armour(op,tmp,op->inv);
  1899.             if (op->contr->eric_server > 0)
  1900.                   esrv_send_item(op, tmp);
  1901.              else
  1902.                   draw_inventory(op);
  1903.  
  1904.              return 1;
  1905.     } 
  1906.  
  1907.     new_draw_info(NDI_UNIQUE, 0,op,"First item in inventory is not armour!\n");
  1908.     return 0;
  1909.     
  1910.  
  1911.    case WEAPON_IMPROVER:
  1912.     return check_improve_weapon(op, tmp);
  1913.  
  1914.    case MONEY_CHANGER:
  1915.     if(op->type!=PLAYER)
  1916.       return 0;
  1917.     new_draw_info(NDI_UNIQUE, 0,op,"Applied money changer.");
  1918.     if (tmp->slaying==NULL) {
  1919.       LOG(llevError,"Money changer converts to nothing???\n");
  1920.  /* If this is so critical, we should at least the object and generate
  1921.     a core file */
  1922. /*      kill(getpid(),1);*/
  1923.       return 0;
  1924.     }
  1925.     money_change(op,tmp->slaying);
  1926.     return 1;
  1927.    case CLOCK: {
  1928.        time_t t = time(NULL);
  1929.     strftime(buf, sizeof(buf), "Time is %I:%M %p", localtime(&t));
  1930. #ifdef SOUND_EFFECTS
  1931.        play_sound_player_only(op->contr, SOUND_CLOCK);
  1932. #endif
  1933.        new_draw_info(NDI_UNIQUE, 0,op, buf);
  1934.     return 1;
  1935.    }
  1936.   case MENU: 
  1937.     if (op->type!=PLAYER) return 0;
  1938.     shop_listing(op);
  1939.     return 1;
  1940.   case POWER_CRYSTAL:
  1941.     apply_power_crystal(op,tmp);  /*  see egoitem.c */
  1942.     return 1;
  1943.   case LIGHTER:        /* for lighting torches/lanterns/etc */ 
  1944.     apply_lighter(op,tmp);
  1945.     return 1;
  1946.   case GRAVE:
  1947.     if (op->type != PLAYER)
  1948.       return 0;
  1949.     return make_gravestone (op, tmp);
  1950.   /* Drop a certain amount of gold, and have one item identified */
  1951.   case IDENTIFY_ALTAR:
  1952.     return apply_id_altar(op, tmp);
  1953.   default:
  1954. #if 0
  1955.     if(op->type==PLAYER) {
  1956.       new_draw_info(NDI_UNIQUE, 0,op,
  1957.           "I don't know how to apply the %s.",query_name(tmp));
  1958.     }
  1959. #endif
  1960.     return 0;
  1961.   }
  1962.   return 1;
  1963. }
  1964.  
  1965. void apply_below(object *op) {
  1966.   object *tmp;
  1967.  
  1968.   /* If we are using a container, then lets apply what is in the container
  1969.    * instead of whats on the ground.
  1970.    */
  1971.   if (op->container!=NULL) {
  1972.     for(tmp=op->container->inv;tmp!=NULL&&!apply(op,tmp);tmp=tmp->below);
  1973.   } else
  1974.     for(tmp=op->below;tmp!=NULL&&!apply(op,tmp);tmp=tmp->below);
  1975. }
  1976.  
  1977. int apply_special(object *who,object *op) { /* wear/wield */
  1978.   object *tmp;
  1979.   char buf[MAX_BUF];
  1980.   int i;
  1981.  
  1982.   if(who==NULL) {
  1983.     LOG(llevError,"apply_special() from object without environment.\n");
  1984.     return 1;
  1985.   }
  1986.  
  1987.   if(op->env!=who) {
  1988.     new_draw_info(NDI_UNIQUE, 0,who,"You must get it first.");
  1989.     return 1;
  1990.   }
  1991.   if(QUERY_FLAG(op,FLAG_APPLIED)) {
  1992.     if (QUERY_FLAG(op, FLAG_CURSED) || QUERY_FLAG(op, FLAG_DAMNED))
  1993.     {
  1994.       new_draw_info_format(NDI_UNIQUE, 0, who,
  1995.     "No matter how hard you try, you just can't\nremove %s.",
  1996.           query_name(op));
  1997.       return 1;
  1998.     }
  1999.     CLEAR_FLAG(op, FLAG_APPLIED);
  2000.     switch(op->type) {
  2001.     case WEAPON:
  2002.       if(!change_abil(who,op)) {
  2003.     new_draw_info_format(NDI_UNIQUE, 0, who,
  2004.         "You can't get rid of the %s.",query_name(op));
  2005.         SET_FLAG(op, FLAG_APPLIED);
  2006.         return 1;
  2007.       }
  2008. #ifdef ALLOW_SKILLS /* 'unready' melee weapons skill if it is current skill */ 
  2009.       (void) check_skill_to_apply(who,op);
  2010.       if(QUERY_FLAG(who,FLAG_READY_WEAPON)) 
  2011.         CLEAR_FLAG(who,FLAG_READY_WEAPON); 
  2012. #endif
  2013.       sprintf(buf,"You unwield %s.",query_name(op));
  2014.       break;
  2015. #ifdef ALLOW_SKILLS
  2016.     case SKILL:         /* allows objects to impart skills */
  2017.       if(!change_abil(who,op)) {
  2018.         new_draw_info_format(NDI_UNIQUE, 0, who,
  2019.             "You can't stop using the %s.",query_name(op));
  2020.         SET_FLAG(op, FLAG_APPLIED);
  2021.         return 1;
  2022.       }  
  2023.       if(who->type==PLAYER) {
  2024.         new_draw_info_format(NDI_UNIQUE, 0, who,
  2025.             "You can no longer use the skill: %s.",skills[op->stats.sp].name);
  2026.         who->contr->shoottype=range_none;
  2027.         who->contr->last_value = -1;
  2028.       }  
  2029.       CLEAR_FLAG(who, FLAG_READY_SKILL);
  2030.       who->chosen_skill=NULL;
  2031. /*      sprintf(buf,"You stop using the %s.",query_name(op));*/
  2032.       break;
  2033. #endif
  2034.     case ARMOUR:
  2035.     case HELMET:
  2036.     case SHIELD:
  2037.     case RING:
  2038.     case BOOTS:
  2039.     case GLOVES:
  2040.     case AMULET:
  2041.     case GIRDLE:
  2042.     case BRACERS:
  2043.     case CLOAK:
  2044.       if(!change_abil(who,op)) {
  2045.     new_draw_info_format(NDI_UNIQUE, 0, who,
  2046.         "You can't remove the %s.",query_name(op));
  2047.         SET_FLAG(op, FLAG_APPLIED);
  2048.         return 1;
  2049.       }
  2050.       sprintf(buf,"You unwear %s.",query_name(op));
  2051.       break;
  2052.     case BOW:
  2053.     case WAND:
  2054.     case ROD:
  2055.     case HORN:
  2056. #ifdef ALLOW_SKILLS
  2057.       (void) check_skill_to_apply(who,op);
  2058. #endif
  2059.       sprintf(buf,"You unready %s.",query_name(op));
  2060.       if(who->type==PLAYER) {
  2061.         who->contr->shoottype = range_none;
  2062.         who->contr->last_value = -1;
  2063.       }
  2064.       break;
  2065.     default:
  2066.       sprintf(buf,"You unapply %s.",query_name(op));
  2067.       break;
  2068.     }
  2069.     new_draw_info(NDI_UNIQUE, 0,who,buf);
  2070.     tmp=merge_ob(op,NULL);
  2071.     fix_player(who);
  2072.     if(who->type==PLAYER)
  2073.       if (who->contr->eric_server > 0) {
  2074.       if (tmp) {  /* it was merged */
  2075.           esrv_del_item (who->contr->eric_server, op->count);
  2076.           op = tmp;
  2077.       }
  2078.       esrv_send_item(who, op);
  2079.       } else
  2080.       draw_inventory(who);
  2081.  
  2082.     return 0;
  2083.   }
  2084.   if (QUERY_FLAG(op, FLAG_UNPAID)) {
  2085.     new_draw_info(NDI_UNIQUE, 0,who, "You should pay for it first.\n");
  2086.     return 0;
  2087.   }
  2088.   i=0;
  2089.   for(tmp=who->inv;tmp!=NULL;tmp=tmp->below)
  2090.     if(tmp->type==op->type&&QUERY_FLAG(tmp, FLAG_APPLIED)&&tmp!=op)
  2091.       if(tmp->type==RING&&!i)
  2092.         i=1;
  2093.       else if(apply_special(who,tmp))
  2094.         return 0;
  2095.   if(op->nrof > 1)
  2096.     tmp = get_split_ob(op,op->nrof - 1);
  2097.   else
  2098.     tmp = NULL;
  2099.   switch(op->type) {
  2100.   case WEAPON: {
  2101.     int level=who->level; 
  2102.  
  2103.     if(!QUERY_FLAG(who,FLAG_USE_WEAPON)) {
  2104.       sprintf(buf,"You can't use %s.",query_name(op));
  2105.       if(tmp!=NULL)
  2106.         (void) insert_ob_in_ob(tmp,who);
  2107.       new_draw_info(NDI_UNIQUE, 0,who,buf);
  2108.       return 0;
  2109.     }
  2110.     /* The skill system hands out wc and dam bonuses to fighters
  2111.      * more generously than the old system (see fix_player). Thus
  2112.      * we need to curtail the power of player enchanted weapons. 
  2113.      * I changed this to 1 improvement per "fighter" level/5 -b.t. 
  2114.      * Note:  Nothing should break by allowing this ratio to be different or
  2115.      * using normal level - it is just a matter of play balance.
  2116.      */            
  2117. #ifdef ALLOW_SKILLS
  2118.     if(who->type==PLAYER) { 
  2119.       object *wc_obj=NULL;
  2120.  
  2121.       for(wc_obj=who->inv;wc_obj;wc_obj=wc_obj->below)
  2122.     if(wc_obj->type==EXPERIENCE&&wc_obj->stats.Str) break;
  2123.       if(!wc_obj) 
  2124.     LOG(llevError,"Error: Player: %s lacks wc experience object\n",who->name);
  2125.       else
  2126.     level=wc_obj->level; 
  2127.     } 
  2128.     if(op->last_eat>((level/5)+5)) {  
  2129. #else
  2130.     if(op->last_eat>(level+5)) {    /* peterm:  last eat is used by
  2131.                     the prepare weapon scroll
  2132.                     to state how many times a weapon
  2133.                     has been improved.  It's sort
  2134.                     of like a weapon level.  Setting
  2135.                     a limit here prevents people
  2136.                     from using an enchanted weapon
  2137.                     too unreasonably powerful for them */
  2138. #endif
  2139.                     
  2140.       new_draw_info(NDI_UNIQUE, 0,who,    
  2141.             "That weapon is too powerful for you to use.");
  2142.       new_draw_info(NDI_UNIQUE, 0, who,    "It would consume your soul!.");
  2143.       if(tmp!=NULL)
  2144.         (void) insert_ob_in_ob(tmp,who);
  2145.       return 1;
  2146.       }
  2147.     if( op->level &&  (strncmp(op->name,who->name,strlen(who->name)))) {
  2148.     /* if the weapon does not have the name as the character, can't use it. */
  2149.     /*        (Ragnarok's sword attempted to be used by Foo: won't work) */
  2150.     new_draw_info(NDI_UNIQUE, 0,who,"The weapon does not recognize you as it's owner.");
  2151.         if(tmp!=NULL)
  2152.           (void) insert_ob_in_ob(tmp,who);
  2153.     return 1;
  2154.     }
  2155.     
  2156.  
  2157.     SET_FLAG(op, FLAG_APPLIED);
  2158.  
  2159. #ifdef ALLOW_SKILLS       /*check for melee weapons skill, alter player status.
  2160.                * Note that we need to call this *before* change_abil */
  2161.     if(!check_skill_to_apply(who,op)) return 0;
  2162.     if(!QUERY_FLAG(who,FLAG_READY_WEAPON))
  2163.          SET_FLAG(who, FLAG_READY_WEAPON);
  2164. #endif
  2165.  
  2166.     if(!change_abil(who,op)) {
  2167.       CLEAR_FLAG(op, FLAG_APPLIED);
  2168.       sprintf(buf,"You receive a jolt when you try to wield %s.",
  2169.               query_name(op));
  2170.       new_draw_info(NDI_UNIQUE, 0,who,buf);
  2171.       if(tmp!=NULL)
  2172.         (void) insert_ob_in_ob(tmp,who);
  2173.       return 1;
  2174.     }
  2175.     sprintf(buf,"You wield %s.",query_name(op));
  2176.     break;
  2177.   }
  2178.   case ARMOUR:
  2179.   case HELMET:
  2180.   case SHIELD:
  2181.   case BOOTS:
  2182.   case GLOVES:
  2183.   case GIRDLE:
  2184.   case BRACERS:
  2185.   case CLOAK:
  2186.     if(!QUERY_FLAG(who, FLAG_USE_ARMOUR)) {
  2187.       sprintf(buf,"You can't use %s.",query_name(op));
  2188.       new_draw_info(NDI_UNIQUE, 0,who,buf);
  2189.       if(tmp!=NULL)
  2190.         (void) insert_ob_in_ob(tmp,who);
  2191.       return 0;
  2192.     }
  2193.   case RING:
  2194.   case AMULET:
  2195.     SET_FLAG(op, FLAG_APPLIED);
  2196.     if(!change_abil(who,op)) {
  2197.       CLEAR_FLAG(op, FLAG_APPLIED);
  2198.       sprintf(buf,"You receive a jolt when you try to wear %s.",
  2199.               query_name(op));
  2200.       new_draw_info(NDI_UNIQUE, 0,who,buf);
  2201.       if(tmp!=NULL)
  2202.         (void) insert_ob_in_ob(tmp,who);
  2203.       return 1;
  2204.     }
  2205.     sprintf(buf,"You wear %s.",query_name(op));
  2206.     break;
  2207. #ifdef ALLOW_SKILLS /* this part is needed for skill-tools */ 
  2208.   case SKILL:
  2209.     SET_FLAG(op, FLAG_APPLIED);
  2210.     if(!change_abil(who,op)) {
  2211.       CLEAR_FLAG(op, FLAG_APPLIED);
  2212.       sprintf(buf,"You receive a jolt when you try to use %s.",
  2213.               query_name(op));
  2214.       new_draw_info(NDI_UNIQUE, 0,who,buf);
  2215.       if(tmp!=NULL)
  2216.         (void) insert_ob_in_ob(tmp,who);
  2217.       return 1;
  2218.     }
  2219.     sprintf(buf,"You ready %s.",query_name(op));
  2220.     who->chosen_skill=op;
  2221.     SET_FLAG(who, FLAG_READY_SKILL);
  2222.     break;
  2223. #endif
  2224.  
  2225. /* For new skills/exp system- must have 'missile weapons' skill in order to
  2226.  * weild missile weapons! -b.t. 
  2227.  */
  2228.   case BOW:
  2229. #ifdef ALLOW_SKILLS /*check for missile weapons skill, alter player status */ 
  2230.     SET_FLAG(op, FLAG_APPLIED);
  2231.     if(!check_skill_to_apply(who,op)) return 0; 
  2232. #endif
  2233.   case WAND:
  2234. #ifdef ALLOW_SKILLS
  2235.     SET_FLAG(op, FLAG_APPLIED);
  2236.     if(!check_skill_to_apply(who,op)) return 0; 
  2237. #endif
  2238.     sprintf(buf,"You ready %s.",query_name(op));
  2239.     break;
  2240.   case ROD:
  2241.   case HORN:
  2242. #ifdef ALLOW_SKILLS
  2243.     SET_FLAG(op, FLAG_APPLIED);
  2244.     if(!check_skill_to_apply(who,op)) return 0;
  2245. #endif
  2246.   default:
  2247.     sprintf(buf,"You apply %s.",query_name(op));
  2248.   }
  2249.   if(!QUERY_FLAG(op, FLAG_APPLIED))
  2250.       SET_FLAG(op, FLAG_APPLIED);
  2251.   new_draw_info(NDI_UNIQUE, 0,who,buf);
  2252.   if(tmp!=NULL)
  2253.     tmp = insert_ob_in_ob(tmp,who);
  2254.   fix_player(who);
  2255.   if(op->type != WAND && who->type == PLAYER)
  2256.     SET_FLAG(op,FLAG_BEEN_APPLIED);
  2257.   if (QUERY_FLAG(op, FLAG_CURSED) || QUERY_FLAG(op, FLAG_DAMNED)) {
  2258.     if (who->type == PLAYER) {
  2259.       new_draw_info(NDI_UNIQUE, 0,who, "Oops, it feels deadly cold!");
  2260.       SET_FLAG(op,FLAG_KNOWN_CURSED);
  2261.     }
  2262.   }
  2263.   if(who->type==PLAYER) {
  2264.     if (who->contr->eric_server > 0) {
  2265.       /* if multiple objects were applied, update both slots */
  2266.       if (tmp)            
  2267.     esrv_send_item(who, tmp);
  2268.       esrv_send_item(who, op);
  2269.     } else {
  2270.       draw_inventory(who);
  2271.     }
  2272.   }
  2273.   return 0;
  2274. }
  2275.  
  2276.  
  2277. int auto_apply (object *op) {
  2278.   object *tmp = NULL;
  2279.   int i;
  2280.  
  2281.   switch(op->type) {
  2282.   case SHOP_FLOOR:
  2283.     if (op->arch->randomitems==0) return 0;
  2284.     do {
  2285.       i=10; /* let's give it 10 tries */
  2286.       while((tmp=generate_treasure(op->arch->randomitems,op->stats.exp?
  2287.         op->stats.exp:5))==NULL&&--i);
  2288.       if(tmp==NULL)
  2289.       return 0;
  2290.       if(QUERY_FLAG(tmp, FLAG_CURSED) || QUERY_FLAG(tmp, FLAG_DAMNED))
  2291.       {
  2292.         free_object(tmp);
  2293.         tmp = NULL;
  2294.       }
  2295.     } while(!tmp);
  2296.  
  2297.     tmp->x=op->x,tmp->y=op->y;
  2298.     SET_FLAG(tmp,FLAG_UNPAID);
  2299.     insert_ob_in_map(tmp,op->map);
  2300.     CLEAR_FLAG(op,FLAG_AUTO_APPLY);
  2301.     identify(tmp);
  2302.     break;
  2303.  
  2304.   case TREASURE:
  2305.     while ((op->stats.hp--)>0)
  2306.       create_treasure(op->arch->randomitems, op, GT_ENVIRONMENT,
  2307.     op->stats.exp ? op->stats.exp : 
  2308.     op->map == NULL ?  14: op->map->difficulty,0);
  2309.     remove_ob(op);
  2310.     free_object(op);
  2311.     break;
  2312.   }
  2313.  
  2314.   return tmp ? 1 : 0;
  2315. }
  2316.  
  2317. /* fix_auto_apply goes through the entire map (only the first time
  2318.  * when an original map is loaded) and performs special actions for
  2319.  * certain objects (most initialization of chests and creation of
  2320.  * treasures and stuff).  Calls auto_apply if appropriate.
  2321.  */
  2322.  
  2323. void fix_auto_apply(mapstruct *m) {
  2324.   object *tmp,*above=NULL;
  2325.   int x,y;
  2326.  
  2327.   for(x=0;x<m->mapx;x++)
  2328.     for(y=0;y<m->mapy;y++)
  2329.       for(tmp=get_map_ob(m,x,y);tmp!=NULL;tmp=above) {
  2330.         above=tmp->above;
  2331.  
  2332.     if(QUERY_FLAG(tmp,FLAG_AUTO_APPLY))
  2333.           auto_apply(tmp);
  2334.         else if(tmp->type==TREASURE) {
  2335.       while ((tmp->stats.hp--)>0)
  2336.             create_treasure(tmp->arch->randomitems, tmp, GT_INVENTORY,
  2337.                             m->difficulty,0);
  2338.     }
  2339.     else if(tmp->type==TIMED_GATE) {
  2340.       tmp->speed = 0;
  2341.       update_ob_speed(tmp);
  2342.     }
  2343.         if(tmp && tmp->arch && tmp->type!=PLAYER && tmp->type!=TREASURE &&
  2344.       tmp->arch->randomitems)
  2345.             create_treasure(tmp->arch->randomitems, tmp, GT_INVENTORY,
  2346.                             m->difficulty,0);
  2347.       }
  2348.   for(x=0;x<m->mapx;x++)
  2349.     for(y=0;y<m->mapy;y++)
  2350.       for(tmp=get_map_ob(m,x,y);tmp!=NULL;tmp=tmp->above)
  2351.     if (tmp->type == TRIGGER || tmp->type == TRIGGER_BUTTON ||
  2352.             tmp->type == TRIGGER_PEDESTAL || tmp->type == TRIGGER_ALTAR)
  2353.       check_trigger(tmp);
  2354. }
  2355.  
  2356. /* eat_special_food() - some food may (temporarily) alter
  2357.  * player status. We do it w/ this routine and cast_change_attr().
  2358.  * Note the dircection is set to "99"  so that cast_change_attr()
  2359.  * will only modify the user's status. We shouldnt be able to 
  2360.  * effect others by eating food!
  2361.  * -b.t.
  2362.  */
  2363.  
  2364. void eat_special_food(object *who, object *food) {
  2365.   /* matrix for attacks we can gain protection/immunity too from eating 
  2366.    * be sure to perserve the ordering between at_type[] and sp_type[]! */
  2367.   static int at_type[] = { AT_PHYSICAL, AT_MAGIC, AT_FIRE, AT_ELECTRICITY,
  2368.     AT_COLD, AT_DRAIN, AT_POISON, AT_SLOW, AT_PARALYZE, AT_CANCELLATION,
  2369.     AT_DEPLETE, AT_FEAR }; 
  2370.   static int sp_type[] = { SP_ARMOUR, SP_PROT_MAGIC, SP_PROT_FIRE, 
  2371.     SP_PROT_ELEC, SP_PROT_COLD, SP_PROT_DRAIN, SP_PROT_POISON, 
  2372.     SP_PROT_SLOW, SP_PROT_PARALYZE, SP_PROT_CANCEL, SP_PROT_DEPLETE, 
  2373.     SP_HEROISM }; 
  2374.  
  2375.   /* matrix for stats we can increase by eating */
  2376.   int i, stat[] = { STR, DEX, CON, CHA };
  2377.   int mod_stat[] = {SP_STRENGTH, SP_DEXTERITY, SP_CONSTITUTION, SP_CHARISMA };
  2378.   
  2379.   /* check if food modifies stats of the eater */
  2380.   for(i=0; i<(sizeof(stat)/sizeof(int)); i++)
  2381.      if(get_attr_value(&food->stats, stat[i]))
  2382.           cast_change_attr(who,99,mod_stat[i]);
  2383.  
  2384.   /* check if we can protect the eater */
  2385.   if(food->protected)
  2386.      for(i=0; i<(sizeof(at_type)/sizeof(int)); i++)
  2387.       if(food->protected&at_type[i]) cast_change_attr(who,99,sp_type[i]);
  2388.  
  2389.   /* check for hp, sp change */
  2390.   if(food->stats.hp!=0) 
  2391.      if(QUERY_FLAG(food, FLAG_CURSED)) { 
  2392.          new_draw_info(NDI_UNIQUE, 0,who,"Eck!...that was poisonous!");
  2393.       who->stats.hp -= food->stats.hp;
  2394.      } else { 
  2395.          if(food->stats.hp>0) 
  2396.         new_draw_info(NDI_UNIQUE, 0,who,"You begin to feel better.");
  2397.      else 
  2398.             new_draw_info(NDI_UNIQUE, 0,who,"Eck!...that was poisonous!");
  2399.        who->stats.hp += food->stats.hp;
  2400.      }
  2401.   if(food->stats.sp!=0) 
  2402.      if(QUERY_FLAG(food, FLAG_CURSED)) { 
  2403.          new_draw_info(NDI_UNIQUE, 0,who,"You are drained of mana!");
  2404.      who->stats.sp -= food->stats.sp; 
  2405.          if(who->stats.sp<0) who->stats.sp=0;
  2406.      } else { 
  2407.          new_draw_info(NDI_UNIQUE, 0,who,"You feel a rush of magical energy!");
  2408.      who->stats.sp += food->stats.sp; 
  2409.     /* place limit on max sp from food? */
  2410.      }
  2411. }
  2412.  
  2413.  
  2414. /* apply_lighter() - designed primarily to light torches/lanterns/etc.
  2415.  * Also burns up burnable material too. First object in the inventory is
  2416.  * the selected object to "burn". -b.t.
  2417.  */
  2418.  
  2419. void apply_lighter(object *who, object *lighter) {
  2420.    object *item = who->inv;
  2421.  
  2422.    for(item=who->inv;item;item=item->next)
  2423.     if(!item->invisible&&item!=lighter) break;
  2424.    if(item) {  
  2425.         new_draw_info_format(NDI_UNIQUE, 0,who,
  2426.        "You attempt to light the %s with the %s.",item->name,lighter->name);
  2427.         if(lighter->last_eat && lighter->stats.food) /* lighter is used up */ 
  2428.         lighter->stats.food--; 
  2429.         else if(lighter->last_eat) {           /* no charges left in lighter */ 
  2430.          new_draw_info_format(NDI_UNIQUE, 0,who,"Nothing happens.");
  2431.          return;
  2432.         }
  2433.     save_throw_object(item,AT_FIRE);
  2434.  
  2435.    } else /* nothing to light */ 
  2436.     new_draw_info(NDI_UNIQUE, 0,who,"Nothing happens.");
  2437.  
  2438. }
  2439.